Moving between view controllers using toolbar - swift

This is a beginner question
I want to move to the next view controller (OptionsView) when the button in the toolbar tapped, how can I do it?
var body: some View {
NavigationView {
VStack{
Text(/*#START_MENU_TOKEN#*/"Hello, World!"/*#END_MENU_TOKEN#*/)
}
.navigationTitle("Profile")
.navigationBarTitleDisplayMode(.inline)
.toolbar{
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
OptionsView()
} label: {
Label("Settings", systemImage: "gear")
}
}
}
}
}
}

You can use the isActive property of a NavigationLink to programmatically activate the link. The NavigationLink can use EmptyView as it's label so that it's hidden, since you only need it to be activated via the Button.
Then, inside of your Button's action, instead of trying to insert the view (which should always be in the view hierarchy -- not inside an action), you can set the the #State variable to activate.
struct ContentView : View {
#State private var optionsActive = false
var body: some View {
NavigationView {
VStack{
Text("Hello, World!")
NavigationLink(isActive: $optionsActive) {
OptionsView()
} label: {
EmptyView()
}
}
.navigationTitle("Profile")
.navigationBarTitleDisplayMode(.inline)
.toolbar{
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
optionsActive = true
} label: {
Label("Settings", systemImage: "gear")
}
}
}
}
}
}

Related

Change the color of navigationTitle inside NavigationStack

I would like to change the color of navigationTitle inside NavigationStack.
struct InterestView: View {
var body: some View {
NavigationStack {
VStack {
}
.navigationTitle("interest".uppercased())
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
print("Image tapped!")
} label: {
Text("add".uppercased())
.foregroundColor(Color.primaryColor)
.font(.headline)
}
}
}
}
}
}
I could not find any modifier to change it.
In SwiftUI, you cannot change title color with a simple modifier. You need to change UINavigation Appearance but this will effect globally.
Alternative solution:
You are already using toolbar, so adding title to toolbar is easy as follow. I hope this solves your problem.
struct InterestView: View {
var body: some View {
NavigationStack {
VStack {
}
.toolbar {
ToolbarItemGroup(placement: .principal) {
Text("interest".uppercased())
.foregroundColor(.red)
}
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
print("Image tapped!")
} label: {
Text("add".uppercased())
.foregroundColor(Color.red)
.font(.headline)
}
}
}
}
}
}

How to show a sheet with a NavigationView in SwiftUI

How do you show a sheet with a NavigationView in SwiftUI? This is what I tried, but it doesn't show the navigation bar.
struct ContentView: View {
#State var present = false
var body: some View {
VStack {
Button {
present = true
} label: {
Text("Show Sheet")
}
}
.padding()
.sheet(isPresented: $present) {
NavigationView {
Text("Hello World")
}
.navigationTitle("Title")
}
}
}
The .navigationTitle modifier belongs to the child views of the NavigationView, so you need to move it inside the closure and on the Text, which in this case, is the child view.
struct ContentView: View {
#State var present = false
var body: some View {
VStack {
Button {
present = true
} label: {
Text("Show Sheet")
}
}
.padding()
.sheet(isPresented: $present) {
NavigationView {
Text("Hello World")
.navigationTitle("Title") // <-- Here
}
}
}
}

SwiftUI: Native menu items navigation to view

I have like to use the native navigation menu bar in swiftui but somehow I could not get it to navigate to the settings page.
When I click on Settings menu item, it does show "at setting" but it does not navigate to the view.
Any help would be greatly appreciated.
struct ContentView: View {
#StateObject var vm = LoginViewModel()
#State var selection: Int? = 0
var body: some View {
NavigationView {
ZStack {
if !vm.log_status {
Home()
.toolbar{
ToolbarItem(placement: .navigationBarTrailing) {
Menu {
Button {
print("at home")
} label: {
Label("Home", systemImage: "house.fill")
}
Button {
print("at setting")
self.selection = 1
} label: {
NavigationLink(destination: Text("Settings Page"), tag:1, selection: $selection) { Label("Settings", systemImage: "gearshape.fill")}
}
} label: {
Label(title: { Text("Menu")}, icon: {Image(systemName: "filemenu.and.selection").foregroundColor(Color.black).font(.system(size: 24))})
}
}
}
} else {
Login()
}
}
.navigationTitle("App")
}
}
}
It is not necessary to have the NavigationLink inside a button itself. You can move it within the ZStack and get rid of any label you defined. By doing so, when you tap on the button where "at setting" is printed, you still change the selection value which in return triggers the navigation call. I've made a few changes to your code (Read the comments):
NavigationView {
ZStack {
NavigationLink(destination: Text("Settings Page"), tag:1, selection: $selection) {} // Move the NavigationLink to the ZStack and get rid of any labels set.
if !vm.log_status {
Text("Home")
.toolbar{
ToolbarItem(placement: .navigationBarTrailing) {
Menu {
Button {
print("at home")
} label: {
Label("Home", systemImage: "house.fill")
}
Button {
print("at setting")
self.selection = 1
} label: {
Label("Settings", systemImage: "gearshape.fill") // Keep ONLY the label of the Previous NavigationLink
}
} label: {
Label(title: { Text("Menu")}, icon: {Image(systemName: "filemenu.and.selection").foregroundColor(Color.black).font(.system(size: 24))})
}
}
}
} else {
Text("Login")
}
}
.navigationTitle("App")
}
The result:

SwiftUI: How can I change the Color of Alert Button and NavigationLink back button?

How can I change the Color from the Button in a Alert and the back Button from NavigationLink? To set .accentColor(.init("someColor")) after the Text from the Alert Button doesn't work. To set .accentColor(.init("someColor")) after navigationLink does not work too. What can I do?
The Alert Button:
The Back Button from NavigationLink:
struct ContentView: View {
#State var showSheet = false
#State var alertShouldBeShown = !UserDefaults.standard.bool(forKey: "£Start")
var body: some View {
Button(action: {
self.showSheet.toggle()
}) {
Text("click me")
//.accentColor(colorScheme == .dark ? Image("") : Image("Info-Icon"))
}.sheet(isPresented: $showSheet) {
SheetView(showSheet: self.$showSheet)
}
.alert(isPresented: $alertShouldBeShown, content: {
Alert(title: Text("Headline"),
message: Text("Text"),
dismissButton: Alert.Button.default(
Text("Ok"), action: {
UserDefaults.standard.set(true, forKey: "Start")
}
)
)
})
}
}
struct SheetView: View {
#Binding var showSheet: Bool
var body: some View {
NavigationView {
DetailView()
.navigationBarTitle(Text("Headline"), displayMode: .inline)
.navigationBarItems(trailing: Button(action: {
self.showSheet = false
}) {
Text("Done")
.bold()
})
}.navigationViewStyle(StackNavigationViewStyle())
}
}
struct DetailView: View {
var body: some View {
List {
HStack {
NavigationLink(destination: DetailViewOne()) {
Text("View 1")
}
}
HStack {
NavigationLink(destination: DetailViewTwo()) {
Text("View 2")
}
}
}
}
}
struct DetailViewOne: View {
var body: some View {
Text("1")
}
}
struct DetailViewTwo: View {
var body: some View {
Text("2")
}
}
You can change the NavigationBar accent color by using accentColor but you need to apply it to the SheetView (the root view of a given environment):
SheetView(showSheet: self.$showSheet)
.accentColor(.red)
Unfortunately SwiftUI doesn't allow much of Alert customisation so far.
However, as Alert is built on top of UIKit components (UIAlertController) this also means you can change the appearance of UIView when contained in UIAlertController.
You can put this code in your #main App init or in the SceneDelegate:
UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = .red

.onDisappear() method isn't triggered when clicking the NavigationLink, SwiftUI

NavigationView {
List{
ForEach(self.data.firebaseObj.lists, id: \.self) { item in
NavigationLink(
destination: DetailView(
list: item,
listIndex: self.data.firebaseObj.lists.firstIndex(of: item) ?? -1
).environmentObject(self.data)
){
Text(item.name)
}
}
.onDelete(perform: delete)
}
.navigationBarTitle(Text("Le liste").font(.largeTitle), displayMode: .inline)
.navigationBarItems(
leading: SignOutButton(),
trailing: Button(action: {
self.show_modal = true
}) {Image(systemName: "plus")}.sheet(isPresented: self.$show_modal) {
AddListForm(email: self.session.session!.email!).environmentObject(self.data)
})
}.onAppear(
perform:{
self.data.createList(username: self.session.session!.email!)
})
.onDisappear(
perform: {
self.data.listener.remove()
print("should be removed")
})
That's the code I have and, as written in the title, clicking on the NavigationLink doesn't trigger the .onDisappear() method. Instead, changing to another tab view works fine. Am I doing something wrong or is this just the way it is supposed to work? In the second case, is there a simple way to execute some code when clicking on a NavigationLink?
This is how it is supposed to work, because your DetailView is a subview of your MainView if you use NavigationLink. That is why your MainView isn't really disappearing programmatically speaking.
Nevertheless you can do it like this:
struct ContentView: View {
#State private var showDetailView = false
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailView(), isActive: $showDetailView) {
Button(action: {
print("should be removed")
self.showDetailView = true
}, label: {
Text("Listitem")
})
}
Spacer()
}.navigationBarTitle(Text("MainView"))
}
}
}
struct DetailView: View {
var body: some View {
Text("DetailView")
}
}