ToolbarItem(placement: .bottomBar) {
NavigationLink(
destination: NoteView(note: Note())
) {
Image(systemName: "square.and.pencil")
}
}
This code is not working as expected: no action is being performed when I tap on the image.
Any idea why or way around?
A possible workaround is to move the NavigationLink outside the toolbar and activate with the isActive parameter:
struct ContentView: View {
#State var linkActive = false
var body: some View {
NavigationView {
Text("Test")
.background(
NavigationLink(destination: Text("Destination"), isActive: $linkActive) {}
)
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button(action: {
linkActive = true
}) {
Image(systemName: "square.and.pencil")
}
}
}
}
}
}
Related
I am making an app where the first view the users see is a home screen with buttons that takes them to a second view. One of the second views present the user with a list of items. When the user clicks on one of these items the user comes to a detailed view of the item. When the user comes to the detailed view he is unfortunately presented with two toolbar buttons in the corner as can be seen here:
.
I know that one of the solutions is to only have one navigationview and that solves my problem. But I need to have toolbar items in my listview to be able to add more items, sort the list and have the list searchable which I'm not able to do without navigationView. I Have tried using scrollView and NavigationStack but it comes out blank.
Does anyone have an idea how to work with mulitple views, not getting double up "back buttons" on the toolbar and still have other toolbar items?
View one: (Home Screen):
NavigationView {
ZStack {
VStack {
Text(title)
.font(.custom("Glacial Indifference", size: 34, relativeTo: .headline).weight(.bold))
.multilineTextAlignment(.leading)
.foregroundColor(.white)
.tracking(10)
.padding(8)
.background(
Rectangle()
.fill(.gray)
.frame(width: 1000, height: 150)
.ignoresSafeArea()
.opacity(0.5))
Spacer()
}
VStack {
NavigationLink {
MapView()
} label: {
Buttons(str: "Cheese Map")
}
.padding(.bottom, 200)
}
VStack {
NavigationLink {
TabView()
} label: {
Buttons(str: "Cheese List")
}
.padding(.bottom, 400)
}
Second View (list):
NavigationView {
List {
ForEach(items, id: \.id) { item in
NavigationLink {
ItemView(item: item)
} label: {
ListItem(item: item)
}
}
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
showingAddItem = true
} label: {
Image(systemName: "plus")
Text("Add Item")
.font(.footnote)
.italic()
}
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Menu("Sort") {
Picker("Filter Options", selection: $selectedSort) {
ForEach(sortOptions, id: \.self) {
value in
Text(value)
.tag(value)
}
}
}
.onChange(of: selectedSort) { _ in
let sortBy = sorts[sortOptions.firstIndex(of: selectedSort)!]
items.sortDescriptors = sortBy.descriptors
}
}
}
.sheet(isPresented: $showingAddItems) {
AddItemsView(items: Items())
}
.navigationTitle("Item List")
.searchable(text: $searchText)
}
}
}
DetailView:
ScrollView {
ZStack {
VStack {
//More code...
Both .toolbar and .searchable find the nearest enclosing NavigationView automatically. You do not need a NavigationView in your list view.
Here's a self-contained demo. It looks like this:
Here's the code:
import SwiftUI
import PlaygroundSupport
struct HomeScreen: View {
var body: some View {
NavigationView {
List {
NavigationLink("Cheese Map") { Text("Map") }
NavigationLink("Cheese List") { ListView() }
}
.navigationTitle("Home Screen")
}
.navigationViewStyle(.stack)
}
}
struct ListView: View {
#State var items = ["Cheddar", "Swiss", "Edam"]
#State var search: String = ""
var filteredItems: [String] {
return items.filter {
search.isEmpty
|| $0.localizedCaseInsensitiveContains(search)
}
}
var body: some View {
List(filteredItems, id: \.self) {
Text($0)
}
.searchable(text: $search)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
withAnimation {
items.append("Gouda")
}
} label: {
Label("Add Item", systemImage: "plus")
}
.disabled(items.contains("Gouda"))
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Menu("Sort") {
Button("Ascending") {
withAnimation {
items.sort()
}
}
Button("Descending") {
withAnimation {
items.sort()
items.reverse()
}
}
}
}
}
.navigationTitle("Cheese List")
}
}
PlaygroundPage.current.setLiveView(HomeScreen())
I'm new in SwiftUI. I would like on the top left in the corner a Button next to the Picker. But when I place the Button, the Picker moves to the right and the Button is to nearly on the edge. How can I place the Button flush over the Headline and the Picker perfectly in the middle from iPhone Nodge?
Before:
After:
import SwiftUI
import Combine
struct ContentView: View {
#State var Selection = UserDefaults.standard.integer(forKey: "Picker")
#State var Detail = false
var body: some View {
VStack {
HStack {
Button(action: {
self.Detail.toggle()
}) {
Text("click")
}.sheet(isPresented: $Detail) {
SettingView(showSheetView: self.$Detail, selection: $Selection)
}
Picker("", selection: $Selection) {
Text("Selection1").tag(0)
Text("Selection2").tag(1)
}
.pickerStyle(SegmentedPickerStyle()).padding(.horizontal, 89)
.onReceive(Just(Selection)) {
UserDefaults.standard.set($0, forKey: "Picker")
}
}
PageOne()
}
}
}
struct PageOne: View {
var body: some View {
NavigationView {
VStack {
Text("some Text")
}.navigationTitle("Headline")
}
}
}
struct SettingView: View {
#Binding var showSheetView: Bool
#Binding var selection: Int
var body: some View {
NavigationView {
Text("Test")
.navigationBarTitle(Text("Select something"))
.navigationBarItems(trailing: Button(action: {
self.showSheetView = false
}) {
Text("Ok")
.bold()
})
}
}
}
you can use a ZStack to show your Button and Picker without pushing them.
something like this:
var body: some View {
VStack {
ZStack {
HStack {
Button(action: {
self.Detail.toggle()
}) {
Text("click")
}.sheet(isPresented: $Detail) {
SettingView(showSheetView: self.$Detail, selection: $Selection)
}
Spacer()
}
HStack {
Spacer()
Picker("", selection: $Selection) {
Text("Selection1").tag(0)
Text("Selection2").tag(1)
}
.pickerStyle(SegmentedPickerStyle()).padding(.horizontal, 89)
.onReceive(Just(Selection)) {
UserDefaults.standard.set($0, forKey: "Picker")
}
Spacer()
}
}
PageOne()
}
}
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")
}
}
I want to open a new view using a button that is in a navigationBarItems. I put my code. Thanks for your help.
struct ClienteView: View {
var body: some View {
NavigationView {
List(clientes) { cliente in
NavigationLink(destination: DetallesClienteView(objCliente: cliente)){
DetallesCliente(objCliente: cliente)
}
}
.navigationBarTitle(Text("Clientes"), displayMode: .inline)
.navigationBarItems(trailing:
Button(action: {
}) {
Image(systemName: "person.badge.plus")
}
)
}
}
}
You can do this kind of thing:
.navigationBarItems(trailing:
NavigationLink(destination: SecondView(), label: {
Image(systemName: "person.badge.plus")
})
)
I have a view that has navigation bar items and I embed that view in a TabView. But when doing that, the bar items no longer appear. If I call the view outside of a TabView everything works as expected.
Below a small sample project to illustrate my issue, note that the TabView is not called on the initial ContentView but later down:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView{
NavigationLink(destination: WarehouseOrderTabView()){
Text("Click me")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct WarehouseOrderTabView: View {
var body: some View {
TabView{
TabView1().navigationBarTitle("Dashboard")
.tabItem {
Image(systemName: "gauge")
Text("Dashboard")
}
TabView2().navigationBarTitle("Orders")
.tabItem {
Image(systemName: "list.dash")
Text("Orders")
}
}
}
}
struct TabView1: View {
var body: some View {
Text("TabView 1")
//I would expect to see those bar items when displaying tab 1
.navigationBarItems(trailing: (
HStack{
Button(action: {
}, label: {
Image(systemName: "arrow.clockwise")
.font(.title)
})
.padding(.init(top: 0, leading: 0, bottom: 0, trailing: 20))
Button(action: {
}, label: {
Image(systemName: "slider.horizontal.3")
.font(.title)
})
}
))
}
}
struct TabView2: View {
var body: some View {
Text("TabView 2")
}
}
What am I missing here?
A NavigationView can be embedded in a TabView and not vice-versa.
TabView contains different tabItem() (at most 5) that can contain your views.
This is how you can use it.
TabView1.swift
struct TabView1: View {
var body: some View {
NavigationView {
Text("TabView 1")
.navigationBarTitle("Dashboard")
.navigationBarItems(trailing:
HStack {
Button(action: {
// more code here
}) {
Image(systemName: "arrow.clockwise")
.font(.title)
}
Button(action: {
// more code here
}) {
Image(systemName: "slider.horizontal.3")
.font(.title)
}
}
)
}
}
}
TabView2.swift
struct TabView2: View {
var body: some View {
NavigationView {
NavigationLink(destination: YourNewView()) {
Text("TabView 1")
}
.navigationBarTitle("Orders")
}
}
}
ContentView.Swift
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
TabView1()
.tabItem {
Image(systemName: "gauge")
Text("Dashboard")
}
TabView2()
.tabItem {
Image(systemName: "list.dash")
Text("Orders")
}
}
}
}
Hope it helps :)