Showing the Tab view colour on appear in swift UI - swiftui

I have the Tab view which is embedded into navigation view . By default When I selected the any of the tab view , the colour is green but I am expecting it should be red .
Here is the code ..
import SwiftUI
struct ContentView: View {
#State private var selection = 0
//#EnvironmentObject private var viewModel: FruitsViewModel
var body: some View {
TabView(selection: $selection) {
NavigationView () {
TabListView().navigationBarTitle("Fruit List ", displayMode: .inline)
//.environmentObject(viewModel)
.toolbarBackground(Color.blue,for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar)
.accentColor(.red)
.onAppear() {
UITabBar.appearance().barTintColor = .red
}
}.tabItem {
Image(systemName: "house.fill")
Text("List View")
}.tag(0)
}
}
}
Here is the screenshot ..

You should call the .accentColor(.red) at Tab View not inside the Navigation view.

Related

SwiftUI how to align the navigation bar title on center when user taps on a navigation link?

I have a TabView in a struct. I add a NavigationView and a NavigationLink. When the view shows up the navigation bar is centered. When i tap on the navigation link the text is on the leading side. How can i make the navigation bar text align to center after i tap the navigation link in iOS 16 and above? I have searched stackoverflow and nothing seems to work in iOS 16 with this specific implementation i am posting below. Any help appreciated.
import Foundation
import SwiftUI
public struct TabViewTest: View {
#State var selectedTab: Int = 0
public var body: some View {
TabView (selection: $selectedTab) {
NavigationView {
NavigationLink(destination: Text("destination"))
{
FeedView(selectedTab: $selectedTab)
.navigationBarTitle("Feed", displayMode: .inline)
.toolbar {
ToolbarItemGroup {
Image(systemName :"magnifyingglass.circle")
.onTapGesture {
selectedTab = 1
}
}
}
}
}
.tabItem {
Text("Feed")
.foregroundColor(.white)
}
.tag(0)
}
}
struct ProfileView: View {
#Binding var selectedTab: Int
var body: some View {
ZStack {
Color.white.ignoresSafeArea()
VStack {
Text("Nav link test tap anywhere")
.font(.largeTitle)
.foregroundColor(.white)
}
}
}
}

SwiftUI How to change the NavigationBarTitle and add a button from a child form

I have a mainview which has 2 tabs. I placed the navigationView at the master page so I can access to its functionality in the child views. However, the title is never successfully assigned to the master view.
The second objective is adding a button on the navigation button from the child view. However, the form doesn't render it.
Here is the code. Could you please help me with changing the title from the child view and adding a button to NavigationView from the child view?
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView{
MainView()
.navigationBarTitle(Text("App Title"), displayMode: .inline)
}
}
}
struct MainView: View {
var body: some View {
TabView(){
DashboardView()
.navigationBarTitle(Text("Dashboard"), displayMode: .inline)
.tabItem{
//Image(systemName: "list.dash")
Image(systemName: "chart.pie")
Text("Dashboard")
}.tag(0)
AssignmentView()
.navigationBarTitle(Text("Assignments"), displayMode: .inline)
.tabItem{
Image(systemName: "briefcase")
Text("Assignments")
}.tag(1)
}
}
}
struct DashboardView: View {
var body: some View {
Text("Dashboard View")
.navigationBarTitle(Text("Dashboard View Title"), displayMode: .inline)
}
}
struct AssignmentView: View {
var body: some View {
Text("Assignment View")
.navigationBarTitle(Text("Assignments View Title"), displayMode: .inline)
.navigationBarItems(trailing: Button(action: {
print("Dashboard button click")
}) {
Text("Submit")
})
}
}
For proper navigation features work there should be only one NavigationView in view stack. I assume you just need to remove first NavigationView, because your MainView is TabView container
struct ContentView: View {
var body: some View {
MainView()
}
}
At least for me, such variant gives native look&feel.
I removed the NavView from the MainView and added NavViews to the subviews with the help of new struct NavigationTab.
struct NavigationTab<Title, Content>: View where Title: StringProtocol, Content: View {
var title: Title
var content: () -> Content
var body: some View {
NavigationView {
content()
.navigationBarTitle(Text(title), displayMode: .inline)
}
}
}
The tab items now look like
NavigationTab(title: "Dashboard" ) {
DashboardView()
.navigationBarItems(leading: Button(action: {
self.isDrawerOpen.toggle()
}) {
Image(systemName: "sidebar.left")
})
}
.tabItem{
Image(systemName: "chart.pie")
Text("Dashboard")
}.tag(1)
I solved an initial problem of adding button on the NavView by replicating DrawerOpen Button in multiple tabs and assign the same "isDrawerOpen" variable.
But I still have a use case in the process where I need to add a button to the NavView.trailing for Submitting. Is there a way to add a button in a subview (for example DashboardView calls another view)?

SwiftUI, setting title to child views of TabView inside of NavigationView does not work

Why I am putting TabView into a NavigationView is because I need to hide the bottom tab bar when user goes into 2nd level 'detail' views which have their own bottom action bar.
But doing this leads to another issue: all the 1st level 'list' views hosted by TabView no longer display their titles. Below is a sample code:
import SwiftUI
enum Gender: String {
case female, male
}
let members: [Gender: [String]] = [
Gender.female: ["Emma", "Olivia", "Ava"], Gender.male: ["Liam", "Noah", "William"]
]
struct TabItem: View {
let image: String
let label: String
var body: some View {
VStack {
Image(systemName: image).imageScale(.large)
Text(label)
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
TabView {
ListView(gender: .female).tag(0).tabItem {
TabItem(image: "person.crop.circle", label: Gender.female.rawValue)
}
ListView(gender: .male).tag(1).tabItem {
TabItem(image: "person.crop.circle.fill", label: Gender.male.rawValue)
}
}
}
}
}
struct ListView: View {
let gender: Gender
var body: some View {
let names = members[gender]!
return List {
ForEach(0..<names.count, id: \.self) { index in
NavigationLink(destination: DetailView(name: names[index])) {
Text(names[index])
}
}
}.navigationBarTitle(Text(gender.rawValue), displayMode: .inline)
}
}
struct DetailView: View {
let name: String
var body: some View {
ZStack {
VStack {
Text("profile views")
}
VStack {
Spacer()
HStack {
Spacer()
TabItem(image: "pencil.circle", label: "Edit")
Spacer()
TabItem(image: "minus.circle", label: "Delete")
Spacer()
}
}
}
.navigationBarTitle(Text(name), displayMode: .inline)
}
}
What I could do is to have a #State var title in the root view and pass the binding to all the list views, then have those list views to set their title back to root view on appear. But I just don't feel so right about it, is there any better way of doing this? Thanks for any help.
The idea is to join TabView selection with NavigationView content dynamically.
Demo:
Here is simplified code depicting approach (with using your views). The NavigationView and TabView just position independently in ZStack, but content of NavigationView depends on the selection of TabView (which content is just stub), thus they don't bother each other. Also in such case it becomes possible to hide/unhide TabView depending on some condition - in this case, for simplicity, presence of root list view.
struct TestTabsOverNavigation: View {
#State private var tabVisible = true
#State private var selectedTab: Int = 0
var body: some View {
ZStack(alignment: .bottom) {
contentView
tabBar
}
}
var contentView: some View {
NavigationView {
ListView(gender: selectedTab == 0 ? .female : .male)
.onAppear {
withAnimation {
self.tabVisible = true
}
}
.onDisappear {
withAnimation {
self.tabVisible = false
}
}
}
}
var tabBar: some View {
TabView(selection: $selectedTab) {
Rectangle().fill(Color.clear).tag(0).tabItem {
TabItem(image: "person.crop.circle", label: Gender.female.rawValue)
}
Rectangle().fill(Color.clear).tag(1).tabItem {
TabItem(image: "person.crop.circle.fill", label: Gender.male.rawValue)
}
}
.frame(height: 50) // << !! might be platform dependent
.opacity(tabVisible ? 1.0 : 0.0)
}
}
This maybe a late answer, but the TabView items need to be assigned tag number else binding selection parameter won't happen. Here is how I do the same thing on my project:
#State private var selectedTab:Int = 0
private var pageTitles = ["Home", "Customers","Sales", "More"]
var body: some View {
NavigationView{
TabView(selection: $selectedTab, content:{
HomeView()
.tabItem {
Image(systemName: "house.fill")
Text(pageTitles[0])
}.tag(0)
CustomerListView()
.tabItem {
Image(systemName: "rectangle.stack.person.crop.fill")
Text(pageTitles[1])
}.tag(1)
SaleView()
.tabItem {
Image(systemName: "tag.fill")
Text(pageTitles[2])
}.tag(2)
MoreView()
.tabItem {
Image(systemName: "ellipsis.circle.fill")
Text(pageTitles[3])
}.tag(3)
})
.navigationBarTitle(Text(pageTitles[selectedTab]),displayMode:.inline)
.font(.headline)
}
}

SwiftUI TabBar Color

How can one set the tabbar color? Assigning the color black results only with a grey bar for example.
This is for SwiftUI.
Specify dark mode is not a suitable work around.
struct ContentView: View {
#State private var selection = 1
init() {
UITabBar.appearance().backgroundColor = UIColor.blue
UITabBar.appearance().backgroundImage = UIImage()
//UITabBar.appearance().isTranslucent = false
//UITabBar.appearance().shadowImage = UIImage()
}
var body: some View {
TabView {
ClockView()
.tabItem {
Image("clock")
Text("Clock")
}.tag(0)
PlanetsNowView()
.tabItem {
Image("clock")
Text("Now")
}.tag(1)
SettingsView()
.tabItem {
Image("settings")
Text("Settings")
}.tag(2)
}
.accentColor(.white)
.opacity(1)
//.environment(\.colorScheme, .dark)
}
}
This is the initializer to create a black tab bar in your SwiftUI View.
import SwiftUI
struct ContentView: View {
init() {
setupTabBar()
}
var body: some View {
TabView {
//Your tab bar items
}
}
}
//MARK: - Tab bar view appearance
extension ContentView {
func setupTabBar() {
UITabBar.appearance().barTintColor = .black
UITabBar.appearance().tintColor = .blue
UITabBar.appearance().layer.borderColor = UIColor.clear.cgColor
UITabBar.appearance().clipsToBounds = true
}
}
If you want to change the color depending on the user light/dark mode settings:
Open 'Assets.xcassets' folder
Right click on your assets panel
Choose 'New Color Set'
Open your attribute inspector panel of the new color
Select 'Appearances'
Choose 'Any, Dark'
You will have now two colored squares where you have to choose your light mode color for the first one, and the dark mode one for the second one.
To use it in your code while initializing your tab bar, change the line that defines the barTintColor with the name of your new set of light/dark mode color.
UITabBar.appearance().barTintColor = UIColor(named: "<your color name>")
Add UITabBar.appearance().barTintColor = UIColor.blue in the initialiser.
Not be found in Xcode code assist however.
struct ContentView: View {
#State private var selection = 1
init() {
UITabBar.appearance().barTintColor = UIColor.blue
UITabBar.appearance().tintColor = .green
}
var body: some View {
TabView (selection:$selection){
Text("The First Tab")
.tabItem {
Image(systemName: "1.square.fill")
Text("First")
}
.tag(1)
Text("Another Tab")
.tabItem {
Image(systemName: "2.square.fill")
Text("Second")
}.tag(2)
Text("The Last Tab")
.tabItem {
Image(systemName: "3.square.fill")
Text("Third")
}.tag(3)
}
.font(.headline)
.accentColor(.white)
}
}

SwiftUI dismiss modal sheet presented from NavigationView (Xcode Beta 5)

I am attempting to dismiss a modal view presented via a .sheet in SwiftUI - called by a Button which is within a NavigationViews navigationBarItems, as per below:
struct ModalView : View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
Button(action: {
self.presentationMode.value.dismiss()
}, label: { Text("Save")})
}
}
struct ContentView : View {
#State var showModal: Bool = false
var body: some View {
NavigationView {
Text("test")
.navigationBarTitle(Text("Navigation Title Text"))
.navigationBarItems(trailing:
Button(action: {
self.showModal = true
}, label: { Text("Add") })
.sheet(isPresented: $showModal, content: { ModalView() })
)
}
}
}
The modal does not dismiss when the Save button is tapped, it just remains on screen. The only way to get rid of it is swiping down on the modal.
Printing the value of self.presentationMode.value always shows false so it seems to think that it hasn't been presented.
This only happens when it is presented from the NavigationView. Take that out and it works fine.
Am I missing something here, or is this a beta issue?
You need to move the .sheet outside the Button.
NavigationView {
Text("test")
.navigationBarTitle(Text("Navigation Title Text"))
.navigationBarItems(trailing:
Button("Add") {
self.showModal = true
}
)
.sheet(isPresented: $showModal, content: { ModalView() })
}
You can even move it outside the NavigationView closure.
NavigationView {
Text("test")
.navigationBarTitle(Text("Navigation Title Text"))
.navigationBarItems(trailing:
Button("Add") { self.showModal = true }
)
}
.sheet(isPresented: $showModal, content: { ModalView() })
Notice you can also simplify the Button call if you have a simple text button.
The solution is not readily apparent in the documentation and most tutorials opt for simple solutions. But I really wanted a button in the NavigationBar of the sheet that would dismiss the sheet. Here is the solution in six steps:
Set the DetailView to not show.
Add a button to set the DetailView to show.
Call the .sheet(isPresented modifier to display the sheet.
Wrap the view that will appear in the sheet in a NavigationView because we want to display a .navigationBarItem button.
PresentationMode is required to dismiss the sheet view.
Add a button to the NavBar and call the dismiss method.
import SwiftUI
struct ContentView: View {
// 1
#State private var showingDetail = false
var body: some View {
VStack {
Text("Hello, world!")
.padding()
Button("Show Detail") {
showingDetail = true // 2
}
// 3
.sheet(isPresented: $showingDetail) {
// 4
NavigationView {
DetailView()
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct DetailView: View {
// 5
#Environment(\.presentationMode) var presentationMode
var body: some View {
Text("Detail View!")
// 6
.navigationBarItems(leading: Button(action: {
presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "x.circle")
.font(.headline)
.foregroundColor(.accentColor)
})
}
}