SwiftUI .toolbar disappears after following NavigationLink and coming back - swiftui

I've added a .toolbar to the top level of a NavigationView that will eventually be used to select items in a list without using swipe gestures (up button, down button, etc.). I also have a .navigationBar going on, to access other views for Account and Settings.
For the most part it's looking really good, but when I follow a NavigationLink (in .navigationBarItems) within NavigationView, and then use the built-in back navigation, my .toolbar disappears from the top level.
Am I putting the .toolbar in the wrong place? It feels like a problem with .navigationViewStyle(StackNavigationViewStyle()) because when I comment that out, the toolbar will not disappear upon navigation... but I don't like how the default behavior works in landscape so I'm relying on it.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
List {
Group {
Section(header: Text("List Items").foregroundColor(.gray).font(.footnote)) {
Text("List Item One")
Text("List Item Two")
Text("List Item Three")
}
}
}.navigationTitle("Top Level List").navigationBarTitleDisplayMode(.inline)
.ignoresSafeArea(.all)
// MARK: NAVBAR
.navigationBarItems(
leading:
NavigationLink(destination: UserView()) {
Image(systemName: "person.crop.circle").font(.title2)
},
trailing:
NavigationLink(destination: SettingsView()) {
Image(systemName: "gear").font(.title2)
})
//MARK: - CONTENT NAV
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button(action: {}, label: {Label("Mute", systemImage: "speaker.slash.fill")})
Spacer()
Button(action: {}, label: {Label("Repeat", systemImage: "arrow.clockwise")})
Spacer()
Button(action: {}, label: {Label("Previous", systemImage: "arrow.up")})
Spacer()
Button(action: {}, label: {Label("Next", systemImage: "arrow.down")})
Spacer()
Button(action: {}, label: {Label("Select", systemImage: "arrow.right")})
}
}
}.navigationViewStyle(StackNavigationViewStyle())
}
}
struct UserView: View {
#State private var username: String = ""
#State private var password: String = ""
var body: some View {
Form {
TextField("Username", text: $username)
SecureField("Password", text: $password)
}
.navigationBarTitle("Account").font(.subheadline)
}
}
struct SettingsView: View {
#State private var setting1: String = ""
#State private var setting2: String = ""
var body: some View {
Form {
TextField("Setting One", text: $setting1)
SecureField("Setting Two", text: $setting2)
}
.navigationBarTitle("Settings").font(.subheadline)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

You right, it's in a wrong place. Here is how it should be if you need a toolbar always shown:
struct ContentView: View {
var body: some View {
NavigationView {
List {
Group {
Section(header: Text("List Items").foregroundColor(.gray).font(.footnote)) {
Text("List Item One")
Text("List Item Two")
Text("List Item Three")
}
}
}.navigationTitle("Top Level List").navigationBarTitleDisplayMode(.inline)
.ignoresSafeArea(.all)
// MARK: NAVBAR
.navigationBarItems(
leading:
NavigationLink(destination: UserView()) {
Image(systemName: "person.crop.circle").font(.title2)
},
trailing:
NavigationLink(destination: SettingsView()) {
Image(systemName: "gear").font(.title2)
})
//MARK: - CONTENT NAV
}.navigationViewStyle(StackNavigationViewStyle())
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button(action: {}, label: {Label("Mute", systemImage: "speaker.slash.fill")})
Spacer()
Button(action: {}, label: {Label("Repeat", systemImage: "arrow.clockwise")})
Spacer()
Button(action: {}, label: {Label("Previous", systemImage: "arrow.up")})
Spacer()
Button(action: {}, label: {Label("Next", systemImage: "arrow.down")})
Spacer()
Button(action: {}, label: {Label("Select", systemImage: "arrow.right")})
}
}
}
}

Related

TabView Navigation SwiftUi

I have such a code and I can't set up navigation
struct ContentView: View {
var body: some View {
TabView{
RootView(title: "Main")
.tabItem{
Image(systemName: "house")
}
RootView(title: "Messages")
.tabItem{
Image(systemName: "message")
}
}
}
}
struct RootView: View{
let title: String
var body: some View{
NavigationView{
List{
ForEach(0..<10, id: \.self){index in
NavigationLink(destination: {
Text("123")
}, label: {
Text("\(index)")
})
}
NavigationLink(destination: {
Text("This is new window")
}, label: {
Text("New window")
})
}
.navigationTitle(title)
}
}
}
Can I do this on SwiftUI 4 so that when I click on a "New Window" list item, that item opens on top of the TabView in a new window? But so that all the other elements of the list open inside the TabView

Container in Picker Menu Style

If I put a HStack in the content of the picker I get tripled rows per HStack. How is it possible to put the content in one row?
Picker: https://imgur.com/a/7GW1sHV
struct ContentView: View{
#State var number = 0
var body: some View{
Menu(content: {
Picker(selection: $number, content: {
Section{
ForEach(0..<5, content: {i in
HStack{
Image(systemName: "house")
Spacer()
Text("number: \(i)")
}
.tag(i)
})
}
Section{
HStack{
Image(systemName: "house")
Spacer()
Text("Section")
}
.tag(6)
}
}, label: {EmptyView()})
}, label: {
Text("number: \(number)")
.frame(width: 100, height: 30)
.background(Color.green)
})
}
}

NavigationView scrolling broken when using TabView

With the below code I get a very weird scrolling behaviour in my TabViews, LoginView is called on app launch:
struct LoginView: View {
#State private var presentContent = false
var body: some View {
return NavigationView {
ZStack{
NavigationLink(
destination: ContentView(),
isActive: $presentContent,
label: {
EmptyView()
})
Button("TEst") {
self.presentContent.toggle()
}
}
}
}
}
struct ContentView: View {
var body: some View {
TabView{
Group{
List{
Text("Item 1")
Text("Item 2")
Text("Item 3")
}
}
.navigationTitle("Transactions")
.tabItem {
Image(systemName: "list.dash")
Text("Transactions")
}
Group{
List{
Text("Item 11")
Text("Item 12")
Text("Item 13")
}
}
.navigationTitle("Summary")
.tabItem {
Image(systemName: "list.dash")
Text("Summary")
}
}
}
}
Any ideas what that might cause?
Here the issue in verbatim: after tapping the button in the LoginView to jump over to the ContentView, I see the first tab. Now I scroll the list up and it goes beyond the screen border which is not correct.
UPDATE: Adding the app launch code below to emphasize the point "LoginView is called on app launch:":
struct TabTestApp: App {
var body: some Scene {
WindowGroup {
LoginView()
}
}
}
Use a NavigationView inside the TabView instead of Group. The login view you have isn't presented or even used. This will fix the scrolling issue.
Edit: Adding a login add additional elements which are unclear. You'd need a data model to handle the login details yourself, but a simple approach could be something like this.
class LoginModel: ObservableObject {
#Published var loggedin: Bool = false
}
struct Login: View {
#ObservedObject var model: LoginModel
#Environment(\.dismiss) var dismiss
var body: some View {
NavigationView {
List {
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
dismiss()
print("if successful login handle here and dismiss")
}, label: {
Label("Close", systemImage: "xmark")
.labelStyle(.iconOnly)
})
}
}
}
}
}
struct ContentView: View {
#StateObject var loginmodel = LoginModel()
#State var sheet: Bool = false
var body: some View {
TabView {
NavigationView {
VStack {
if !loginmodel.loggedin {
Button(action: {
sheet.toggle()
}, label: {
Label("Login", systemImage: "person.circle.fill")
})
} else {
List {
NavigationLink("Item 1", destination: Text("Item 1"))
NavigationLink("Item 2", destination: Text("Item 2"))
NavigationLink(destination: Text("Item 3")) {
Text("Item 3")
}
}
}
}
.navigationTitle("Transactions")
}
.sheet(isPresented: $sheet) {
Login(model: loginmodel)
}
.tabItem {
Label("Transactions", systemImage: "list.dash")
}
NavigationView {
List {
Text("Item 11")
Text("Item 12")
Text("Item 13")
}
.navigationTitle("Summary")
}
.tabItem {
Label("Summary", systemImage: "chart.line.uptrend.xyaxis")
}
}
}
}
struct ContentView: View {
var body: some View {
TabView {
NavigationView {
List {
// Either or navigation link if needed
NavigationLink("Item 1", destination: Text("Item 1"))
NavigationLink("Item 2", destination: Text("Item 2"))
NavigationLink(destination: Text("Item 3")) {
Text("Item 3")
}
}
.navigationTitle("Transactions")
}
.tabItem {
Label("Transactions", systemImage: "list.dash")
}
NavigationView {
List {
Text("Item 11")
Text("Item 12")
Text("Item 13")
}
.navigationTitle("Summary")
}
.tabItem {
Label("Summary", systemImage: "chart.line.uptrend.xyaxis")
}
}
}
}
Ok, I have changed the whole code to
//
// ContentView.swift
// TabTest
//
// Created by Max on 2022-05-04.
//
import SwiftUI
struct LoginView: View {
#Environment(\.presentationMode) var presentationMode
#State private var presentContent = false
var body: some View {
return NavigationView {
ZStack{
Button("Login") {
presentationMode.wrappedValue.dismiss()
}
}
}
}
}
struct ContentView: View {
#State private var isPresented = false
var body: some View {
TabView{
NavigationView{
List{
Text("Item 1")
Text("Item 2")
Text("Item 3")
}
.navigationTitle("Transactions")
.navigationBarBackButtonHidden(true)
}
.tabItem {
Image(systemName: "list.dash")
Text("Transactions")
}
NavigationView{
List{
Text("Item 11")
Text("Item 12")
Text("Item 13")
}
.navigationTitle("Summary")
.navigationBarBackButtonHidden(true)
}
.tabItem {
Image(systemName: "list.dash")
Text("Summary")
}
}
.onAppear{
self.isPresented = true
}
.fullScreenCover(isPresented: $isPresented, content: LoginView.init)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and now it actually seems to work. Never have thought of fullScreenCover - thanks! :)

SwiftUI : NavigationLink and the show Sheet Button in the List item works same time

I have a list item with some text stuff, navigationLink and button to show .sheet.When I click on either navigation link or show sheet button both navigation destination and the sheet appear.How to avoid this behaviour?
Note: This is minimal produceable code.
struct ContentView: View {
#State var shouldSheetShow:Bool = false;
var body: some View {
NavigationView{
List{
VStack(alignment: .leading){
Text("Some Text Stuff")
NavigationLink(
destination: Text("navigation link"),
label: {
Text("Navigate To some view")
.background(Color.green)
})
Button(action: {
self.shouldSheetShow = true
}, label: {
HStack{
Text("Show sheet")
}
.background(Color.blue)
.sheet(isPresented: $shouldSheetShow, content: {
Text("sheet")
})
})
}
.frame(width: 300, height: 150, alignment: .center)
.background(Color.gray)
}
}
}
}
A possible solution is to replace the Button with Text plus an onTapGesture
Replace
Button(action: {
self.shouldSheetShow = true
}, label: {
HStack{
Text("Show sheet")
}
.background(Color.blue)
.sheet(isPresented: $shouldSheetShow, content: {
Text("sheet")
})
})
with
Text("Show sheet")
.background(Color.blue)
.sheet(isPresented: $shouldSheetShow, content: {
Text("sheet")
})
.onTapGesture {
self.shouldSheetShow = true
}

SwiftUI: implementing ZStack inside of navigationBarItems shows navigationBarItems error

I'm trying to implement a ZStack inside of navigationBarItems to load a custom alert. Here is my implementation:
var body: some View {
VStack{
List(self.itemsStore.names){ item in
Text("hello")
}
}
.navigationBarItems(trailing: Button(action: {
ZStack {
ItemsAlert(isShown: $isPresented, text: $text)
}
}, label: {
Image(systemName: "plus")
}))
}
On this line I'm getting this error:
Any of you knows why I'm getting this warning? or if is a work around this error?
I'll really appreciate your help
You cannot put SwiftUI view in closure - it has not sense, view should be in the view hierarchy, button can activate states to manipulate with views, like
var body: some View {
ZStack {
ItemsAlert(isShown: $isPresented, text: $text)
VStack{
List(self.itemsStore.names){ item in
Text("hello")
}
}
}
.navigationBarItems(trailing: Button(action: {
self.isPresented = true // << activate state
}, label: {
Image(systemName: "plus")
}))
}