Im trying to make an app similar to iphones reminders app in terms of UI. I have a view where I have a list that I can add and delete items from, I also have a view for adding an item that allows me to name the item and select some options, and I have another view for when an item in the list is selected and I want to be able to show the name and options I made but it doesn't display. The code for the list view
struct DotView: View {
enum ActiveSheet: String, Identifiable {
case SwiftUIView, EditView
var id: String {
return self.rawValue
}
}
#EnvironmentObject var listViewModel: ListViewModel
#AppStorage("dotApiKey") var selectedDotApi: String = ""
#State var dotName:String = ""
#State var dotNumber:String = ""
#State var selection:String = ""
#State var triggerSelection:String = ""
#State var searchText:String = ""
#State var plugUsername:String = ""
#State var plugPassword:String = ""
#State var toggleNotification:Bool
#State var activeSheet : ActiveSheet? = nil
#Binding var show : Bool
var body: some View {
ZStack{
HStack {
EditButton()
.padding(.leading)
Spacer()
Button(action: {
self.activeSheet = .SwiftUIView
}, label: {
Text("Add")
})
.padding(.trailing)
}
ZStack {
List {
ForEach(listViewModel.dotitems, id:\.dotId){ dotitem in
Button(action: { self.activeSheet = .EditView }, label: {
DotItemListView(dotitem: dotitem)
})
}
.onDelete(perform: listViewModel.deleteItem)
.onMove(perform: listViewModel.moveItem)
.listRowBackground(Color("textBG"))
}.listStyle(PlainListStyle())
.background(Color("textBG"))
.frame(height: 300)
.cornerRadius(10)
.padding(.horizontal)
}
}
.sheet(item: $activeSheet){ sheet in
switch sheet {
case .SwiftUIView:
SwiftUIView(dotName: dotName, dotNumber: dotNumber, selection: selection, triggerSelection: triggerSelection, searchText: searchText, plugUsername: plugUsername, plugPassword: plugPassword, show: $show)
case .EditView:
EditView(show:$show)
}
}
When I add an item to the list it shows this in each row
struct DotItemListView:View {
let dotitem: DotItem
var body: some View{
HStack {
Text(dotitem.dotName)
Spacer()
Text(dotitem.selection)
Spacer()
Text(dotitem.dotNumber)
Spacer()
}
}
}
This is how I'm adding each item to the list
struct DotItem:Equatable, Codable{
var dotId = UUID().uuidString
let dotName:String
let dotNumber:String
let selection:String
}
class ListViewModel: ObservableObject {
#Published var dotitems: [DotItem] = [] {
didSet {
saveItem()
}
}
let dotitemsKey: String = "dotitems_list"
init() {
getDotItems()
}
func getDotItems() {
guard
let data = UserDefaults.standard.data(forKey: dotitemsKey),
let savedDotItems = try? JSONDecoder().decode([DotItem].self, from: data)
else { return }
self.dotitems = savedDotItems
}
func deleteItem(indexSet: IndexSet){
dotitems.remove(atOffsets: indexSet)
}
func moveItem(from: IndexSet, to: Int){
dotitems.move(fromOffsets: from, toOffset: to)
}
func addItem(dotName: String, dotNumber: String, selection: String){
let newItem = DotItem(dotName: dotName, dotNumber: dotNumber, selection: selection)
dotitems.append(newItem)
print(newItem)
}
func saveItem() {
if let encodedData = try? JSONEncoder().encode(dotitems) {
UserDefaults.standard.set(encodedData, forKey: dotitemsKey)
}
}
}
This is the view that I'm entering the data for each item
struct SwiftUIView: View {
#Environment(\.presentationMode) var presentationMode
#EnvironmentObject var listViewModel: ListViewModel
#AppStorage("dotApiKey") var selectedDotApi: String = ""
#State var dotName:String
#State var dotNumber:String
#State var selection:String
#State var triggerSelection:String
#State var selectedColor = Color.black
#State var searchText:String
#State var plugUsername:String
#State var plugPassword:String
#ObservedObject var vm = getDeviceNames()
#State var triggerDot:Bool = false
#State var toggleOnOff:Bool = false
#State var toggleLightColor:Bool = false
#State var isSearching:Bool = false
#StateObject var camera = CameraModel()
#Binding var show : Bool
var body: some View {
NavigationView {
Form {
Section(header: Text("Info")) {
TextField("Name", text: $dotName)
TextField("Number", text: $dotNumber)
Picker(selection: $selection, label: Text("Discover Plug")) {
ForEach(vm.dataSet, id:\.self) { item in
Text(item.Device).tag(item.Device)
}
}
Toggle(isOn: $isSearching, label: {
Text("Have smart plugs?")
})
if isSearching {
HStack{
Text("Casa")
Spacer()
Button(action: {sendPlugDict()}, label: {
Text("Login")
})
}
TextField("Username", text: $plugUsername)
TextField("Password", text: $plugPassword)
}
}
Section {
Toggle(isOn: $toggleOnOff, label: {
Text("On/Off")
})
}
Section {
Toggle(isOn: $toggleLightColor, label: {
Text("Light Color")
})
if toggleLightColor {
ColorPicker("Choose Light Color", selection: $selectedColor)
}
}
Section {
if listViewModel.dotitems.isEmpty == false {
Toggle(isOn: $triggerDot, label: {
Text("Add a DOT to trigger")
})
if triggerDot {
Picker(selection: $triggerSelection, label: Text("Select DOT")) {
ForEach(listViewModel.dotitems, id:\.dotId){ dotitem in
DotItemListView(dotitem: dotitem)
}
}
}
}
}
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
and this is the view that I'm trying to show the data when any list item is selected which is basically the same as above except in a few places
struct EditView: View {
#Environment(\.presentationMode) var presentationMode
#EnvironmentObject var listViewModel: ListViewModel
#ObservedObject var vm = getDeviceNames()
#State var dataSet = [Result]()
#State var dotName:String = ""
#State var dotNumber:String = ""
#State var selection:String = ""
#State var triggerSelection:String = ""
#State var selectedColor = Color.black
#State var searchText:String = ""
#State var plugUsername:String = ""
#State var plugPassword:String = ""
#State var triggerDot:Bool = false
#State var toggleOnOff:Bool = false
#State var toggleLightColor:Bool = false
#State var isSearching:Bool = false
#Binding var show : Bool
var body: some View {
NavigationView {
Form {
Section(header: Text("Info")) {
TextField(dotName, text: $dotName)
TextField(dotNumber, text: $dotNumber)
Picker(selection: $selection, label: Text("Discorver Plug")) {
ForEach(dataSet, id:\.self) { item in
Text(item.Device).tag(item.Device)
}
}
Toggle(isOn: $isSearching, label: {
Text("Have smart plugs?")
})
if isSearching {
HStack{
Text("Casa")
Spacer()
Button(action: {
SwiftUIView(dotName: dotName, dotNumber: dotNumber, selection: selection, triggerSelection: triggerSelection, searchText: searchText, plugUsername: plugUsername, plugPassword: plugPassword, show: $show).sendPlugDict()}, label: {
Text("Login")
})
}
TextField("Username", text: $plugUsername)
TextField("Password", text: $plugPassword)
}
}
Section {
Toggle(isOn: $toggleOnOff, label: {
Text("On/Off")
})
}
Section {
Toggle(isOn: $toggleLightColor, label: {
Text("Light Color")
})
if toggleLightColor {
ColorPicker("Choose Light Color", selection: $selectedColor)
}
}
Section {
if listViewModel.dotitems.isEmpty == false {
Toggle(isOn: $triggerDot, label: {
Text("Add a DOT to trigger")
})
if triggerDot {
Picker(selection: $triggerSelection, label: Text("Select DOT")) {
ForEach(listViewModel.dotitems, id:\.dotId){ dotitem in
DotItemListView(dotitem: dotitem)
}
}
}
}
}
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
I know this is a lot to go through but any help would be greatly appreciated
use #Binding on the view that you want to pass state to .
View1 :
#State var a = true
View2(a: $a)
View2 :
#Binding var a : Bool
for passing data globally use #EnvoirmentObject :
example :
#main
struct YourApp: App {
#StateObject var session = Session()
var body: some Scene {
WindowGroup {
SplashView()
.environmentObject(session)
}
}
}
Session :
class Session: ObservableObject {
/// user signin state
#Published var isSignedIn : Bool = false
}
View1 ,View2 , View3 .... :
struct SplashView: View {
#EnvironmentObject var session : Session
var body: some View {
VStack{
SignInView()
.opacity(session.isSignedIn ? 0:1)
}
.background(Color.background.ignoresSafeArea())
}
}
Related
Let's say that Item is a CoreData entity:
struct ItemDetailView: View {
#Binding var item: Item?
#Binding var isEditing: Bool
var body: some View{
if isEditing {
TextField( "Name", text: Binding($item.data)! )
}else{
Text(item!.data!)
}
}
}
Error: Value of optional type 'Item?' must be unwrapped to refer to member 'data' of wrapped base type 'Item'
Edit All the code:
import SwiftUI
import CoreData
struct ItemDetailView: View {
#Binding var item: Item?
#Binding var isEditing: Bool
var body: some View{
if isEditing {
TextField( "Name", text: Binding($item.data)! )
}else{
Text(item!.data!)
}
}
}
struct ItemEditorView: View {
#Environment(\.managedObjectContext) private var viewContext
#Environment(\.dismiss) private var dismiss
let isNew: Bool
#State var isEditing: Bool = false
#State var item: Item?
#Binding var newItem: Item?
var body: some View {
if isNew {
}
NavigationView{
ItemDetailView(item: isNew ? $newItem : $item, isEditing: $isEditing)
.toolbar {
ToolbarItem {
Button(isNew ? "Add" : (isEditing ? "Done" : "Edit")) {
//TBI
if isNew {
}
}
}
ToolbarItem(placement:.cancellationAction){
Button("Cancel"){
dismiss()
}
}
}
.navigationTitle("Item Editor")
}
}
}
struct ItemsListView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.data, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
#State var presentNewItemEditorView = false
#State var newItem: Item?
var body: some View {
NavigationView {
VStack{
Text(newItem?.data ?? "nil")
List {
ForEach(items){ item in
NavigationLink(item.data!, destination: ItemEditorView(isNew: false, item:item, newItem: $newItem))
}
}
}
.fullScreenCover(isPresented: $presentNewItemEditorView, content: {
ItemEditorView(isNew: true, isEditing: true, newItem: $newItem)
})
.navigationTitle("Main")
.toolbar {
ToolbarItem {
Button("New goal"){
presentNewItemEditorView = true
}
}
}
.task {
newItem = Item(context: viewContext)
newItem!.data = "New item text"
}
}
}
}
I it unclear what are you trying to achieve. Here are options that will compile.
Value type
struct Item {
var data: String
}
struct ItemDetailView: View {
#Binding var item: Item
#Binding var isEditing: Bool
var body: some View{
if isEditing {
TextField( "Name", text: Binding(projectedValue: $item.data) )
}else{
Text(item.data)
}
}
}
Reference type and value type
class Item {
var data: String? = ""
}
struct ItemDetailView: View {
#Binding var item: Item? // Has no sense, because #Binding does't work with clsses!
#Binding var isEditing: Bool
var body: some View{
if isEditing {
TextField("Name", text: Binding(get: {
item!.data!
}, set: { value in
item?.data = value
}))
} else {
Text(item!.data!)
}
}
}
Implementation by Conny Wals sugested by #vadian
import CoreData
class EditViewModel {
/// **new** instance of item to edit. Don't edit the item, if any, that we pass to VM
var item: Item4
/// Context to use in the isolated changes
let context: NSManagedObjectContext
/// Pass an item if you want to edit one, or nil to generate one
init(item: Item4? = nil){
self.context = PersistenceController.shared.childViewContext()
if let item = item {
self.item = PersistenceController.shared.copyForEditing(of: item, in: context)
} else {
self.item = PersistenceController.shared.newTemporaryInstance(in: context)
}
}
func persist(){
PersistenceController.shared.persist(item)
}
}
import SwiftUI
struct EditItemView: View {
#State var viewModel: EditViewModel
#Environment(\.dismiss) private var dismiss
var body: some View {
NavigationView {
VStack{
TextField( "Item Name", text: Binding(get: {viewModel.item.name ?? ""}, set: {viewModel.item.name = $0}))
.textFieldStyle(RoundedBorderTextFieldStyle())
Spacer()
}
.navigationTitle("Edit Item")
.navigationBarItems(leading: Button("Cancel"){
dismiss()
}, trailing: Button("Save"){
viewModel.persist()
dismiss()
})
}
}
}
struct ItemsView04: View {
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item3.name, ascending: true)],
animation: .default)
private var items: FetchedResults<Item4>
#State var editItemViewIsPresent = false
var body: some View {
NavigationView{
List {
ForEach(items){ item in
NavigationLink(item.name ?? ""){
EditItemView(viewModel: EditViewModel(item: item))
}
}
}
.toolbar {
ToolbarItem {
Button {
editItemViewIsPresent = true
}label:{
Text("+")
}
}
}
.fullScreenCover(isPresented: $editItemViewIsPresent){
EditItemView(viewModel: EditViewModel())
}
}
}
}
I am trying to get data from one view to another.
I can not figure out how to get values from the fourth view array into the Third view.
I am not using storyboards. I tried using #EnvironmentObject but can not make it work. New to coding. In xcode I am using watchos without app.
I tried to strip out most of the code and leave just the important stuff that can be tested. I used NavigationLink(destination: )to transfer between views.
enter code here
class viewFromEveryWhere: ObservableObject {
#Published var testname2: String = "testTTname"
}
struct secondView: View {
var body: some View {
Text("second view")
List(1..<7) {
Text("\($0)")
}
}
}
struct thirdView: View {
#EnvironmentObject var testname2: viewFromEveryWhere
#EnvironmentObject var testSixTestArray: viewFromEveryWhere
#State var sixTestArray:[String] = ["ww","GS","DW","CD","TS","JW",]
var body: some View {
List(sixTestArray, id:\.self) {
Text($0)
}
}
}
struct fourthView: View {
#StateObject var testname2 = viewFromEveryWhere()
#State private var name: String = ""
#State var testSixTestArray:[String] = []
func collectName () {
print("collectName triggered")
if testSixTestArray.count < 5 {
// testSixTestArray.append(name)
print(name)
print(testSixTestArray)
}
// .enviromentObject(testSixTestArray)
}
var body: some View {
VStack(alignment: . leading) {
Text("Type a name")
TextField("Enter your name", text: $name)
Text("Click to add, \(name)!")
// Button("click this if \(name) is correct") {}
Button(action:{
print("Button Tapped")
collectName()
print(testSixTestArray.count)
name = ""
}) {
Text("Add \(name) to list")
}
// .buttonStyle(GrowingButton1())
}
Text("forth view")
// testSixTestArray.append(name)
.environmentObject(testname2)
}
}
/*func presentTextInputControllerWithSuggestions(forLanguage suggestionsHandler:
((String)-> [Any]?)?,
allowedInputMode inputMode:
WKTextInputMode,
completion: #escaping ([Any]?) -> Void) {}
*/
struct ContentView: View {
#State var sixNameArray:[String] = ["","","","","","",]
#State var messageTextBox: String = "Start"
#State var button1: String = "Button 1"
#State var button2: String = "Button 2"
#State var button3: String = "Button 3"
var body: some View {
NavigationView {
VStack{
Text(messageTextBox)
.frame(width: 120, height: 15, alignment: .center)
.truncationMode(.tail)
.padding()
NavigationLink(destination: secondView(),
label:{
Text(button1)
})
.navigationBarTitle("Main Page")
NavigationLink(destination: thirdView(),
label:{
Text(button2)
})
NavigationLink(destination: fourthView(),
label:{
Text(button3)
})
}
}
}
}
enter code here
I'm trying to build out a simple navigation where you can click on items in a link and pop back to the root controller from a sheet view. As you can see from the video below, when I tap on an item in the list, the wrong item is loaded (there's an offset between the row I click and the one that gets highlighted and loaded).
I also get the error SwiftUI encountered an issue when pushing aNavigationLink. Please file a bug.
Here's all my code:
import SwiftUI
struct ContentView: View {
#State var rootIsActive:Bool = false
var body: some View {
NavigationView{
AllProjectView(rootIsActive: self.rootIsActive)
}
.navigationBarTitle("Root")
.navigationViewStyle(StackNavigationViewStyle())
.environment(\.rootPresentationMode, self.$rootIsActive)
}
}
struct AllProjectView: View {
#State var rootIsActive:Bool = false
#State var projects: [String] = ["1", "2", "3"]
var body: some View{
List{
ForEach(projects.indices, id: \.self){ idx in
ProjectItem(name: self.$projects[idx], rootIsActive: self.$rootIsActive)
}
}.navigationBarTitle("All Projects")
}
}
struct ProjectItem: View{
#Binding var name: String
#Binding var rootIsActive: Bool
init(name: Binding<String>, rootIsActive: Binding<Bool>){
self._name = name
self._rootIsActive = rootIsActive
}
var body: some View{
NavigationLink(
destination: ProjectView(name: self.name),
isActive: self.$rootIsActive){
Text(name)
}
.isDetailLink(false)
.padding()
}
}
struct ProjectView: View {
var name: String
#State var isShowingSheet: Bool = false
#Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
#Environment(\.rootPresentationMode) private var rootPresentationMode: Binding<RootPresentationMode>
var body: some View{
VStack{
Text(name)
Button("Show Sheet"){
self.isShowingSheet = true
}
}
.sheet(isPresented: $isShowingSheet){
Button("return to root"){
self.isShowingSheet = false
print("pop view")
self.presentationMode.wrappedValue.dismiss()
print("pop root")
self.rootPresentationMode.wrappedValue.dismiss()
}
}
.navigationBarTitle("Project View")
}
}
// from https://stackoverflow.com/a/61926030/1720985
struct RootPresentationModeKey: EnvironmentKey {
static let defaultValue: Binding<RootPresentationMode> = .constant(RootPresentationMode())
}
extension EnvironmentValues {
var rootPresentationMode: Binding<RootPresentationMode> {
get { return self[RootPresentationModeKey.self] }
set { self[RootPresentationModeKey.self] = newValue }
}
}
typealias RootPresentationMode = Bool
extension RootPresentationMode {
public mutating func dismiss() {
self.toggle()
}
}
You only have one isRootActive variable that you're using. And, it's getting repeated for each item on the list. So, as soon as any item on the list is tapped, the isActive property for each NavigationLink turns to true.
Beyond that, your isRootActive isn't actually doing anything right now, since your "Return to root" button already does this:
self.isShowingSheet = false
self.presentationMode.wrappedValue.dismiss()
At that point, there's nothing more to dismiss -- it's already back at the root view.
My removing all of the root and isActive stuff, you get this:
struct ContentView: View {
var body: some View {
NavigationView{
AllProjectView()
}
.navigationBarTitle("Root")
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct AllProjectView: View {
#State var projects: [String] = ["1", "2", "3"]
var body: some View{
List{
ForEach(projects.indices, id: \.self){ idx in
ProjectItem(name: self.$projects[idx])
}
}.navigationBarTitle("All Projects")
}
}
struct ProjectItem: View{
#Binding var name: String
var body: some View{
NavigationLink(
destination: ProjectView(name: self.name)
){
Text(name)
}
.isDetailLink(false)
.padding()
}
}
struct ProjectView: View {
var name: String
#State var isShowingSheet: Bool = false
#Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
var body: some View{
VStack{
Text(name)
Button("Show Sheet"){
self.isShowingSheet = true
}
}
.sheet(isPresented: $isShowingSheet){
Button("return to root"){
self.isShowingSheet = false
print("pop view")
self.presentationMode.wrappedValue.dismiss()
}
}
.navigationBarTitle("Project View")
}
}
If you had an additional view in the stack, you would need a way to keep track of if the root were active. I've used a custom binding here that converts an optional String representing the project's name to a Bool value that gets passed down the view hierarchy:
struct ContentView: View {
var body: some View {
NavigationView{
AllProjectView()
}
.navigationBarTitle("Root")
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct AllProjectView: View {
#State var projects: [String] = ["1", "2", "3"]
#State var activeProject : String?
func activeBindingForProject(name : String) -> Binding<Bool> {
.init {
name == activeProject
} set: { newValue in
activeProject = newValue ? name : nil
}
}
var body: some View{
List{
ForEach(projects.indices, id: \.self){ idx in
InterimProjectView(name: self.$projects[idx],
isActive: activeBindingForProject(name: self.projects[idx]))
}
}.navigationBarTitle("All Projects")
}
}
struct InterimProjectView: View {
#Binding var name : String
#Binding var isActive : Bool
var body : some View {
NavigationLink(destination: ProjectItem(name: $name, isActive: $isActive),
isActive: $isActive) {
Text("Next : \(isActive ? "true" : "false")")
}
}
}
struct ProjectItem: View {
#Binding var name: String
#Binding var isActive: Bool
var body: some View{
NavigationLink(
destination: ProjectView(name: self.name, isActive: $isActive)
){
Text(name)
}
.isDetailLink(false)
.padding()
}
}
struct ProjectView: View {
var name: String
#Binding var isActive : Bool
#State var isShowingSheet: Bool = false
var body: some View{
VStack{
Text(name)
Button("Show Sheet"){
self.isShowingSheet = true
}
}
.sheet(isPresented: $isShowingSheet){
Button("return to root"){
self.isShowingSheet = false
print("pop root")
self.isActive.toggle()
}
}
.navigationBarTitle("Project View")
}
}
I have gut a simple project with a struct inside of a struct and want to add at first the names and hobbies of a single user and than want to add this user to a whole pool of users. The code is the following:
import SwiftUI
struct User: Identifiable, Hashable {
var id = UUID()
var firstName = ""
var lastName = ""
var hobbiesOfUser = [Hobbies]()
}
struct Hobbies: Identifiable, Hashable {
var id = UUID()
var nameOfHobby = ""
var nameClub = ""
}
class UsersStorage: ObservableObject {
#Published var users = [User]()
}
struct ContentView: View {
#EnvironmentObject var userStorage: UsersStorage
#State private var isPresented = false
var body: some View {
NavigationView {
List(userStorage.users) { singleUser in
VStack {
HStack {
Text(singleUser.firstName)
Text(singleUser.lastName)
}
}
}
.navigationBarItems(trailing:
Button(action: {
self.isPresented = true
}) {
Text("New User")
}.sheet(isPresented: $isPresented, onDismiss: {
self.isPresented = false
}) {
AddUserView(isPresented: self.$isPresented, user: User()).environmentObject(self.userStorage)
}
)
}
}
}
struct AddUserView: View {
#EnvironmentObject var userStorage: UsersStorage
#Binding var isPresented: Bool
#State var user: User
#State var hobbiesOfUser = [Hobbies]()
var body: some View {
NavigationView {
VStack {
Text("First Name")
TextField("First Name", text: $user.firstName)
Text("Last Name")
TextField("Last Name", text: $user.lastName)
NavigationLink(destination: AddHobbieView(hobbie: Hobbies())) {
Text("Add New Hobbie")
}
List(user.hobbiesOfUser) { singleHobbie in
VStack {
HStack {
Text(singleHobbie.nameOfHobby)
Text(singleHobbie.nameClub)
}
}
}
HStack {
Button(action: {
self.isPresented = false
}){
Text("Cancel")
}
Button(action: {
self.userStorage.users.append(self.user)
self.isPresented = false
}){
Text("Save")
}
}
}
}
}
}
struct AddHobbieView: View {
#EnvironmentObject var userStorage: UsersStorage
#State var hobbie: Hobbies
var body: some View {
VStack {
Text("Hobby")
TextField("First Name", text: $hobbie.nameOfHobby)
Text("Club")
TextField("Last Name", text: $hobbie.nameClub)
HStack {
Button(action: {
// self.userStorage.users.append(self.hobbie)
}){
Text("Cancel")
}
Button(action: {
}){
Text("Save")
}
}
}
}
}
My question is: how can I add hobbies to the list in the AddUserView and get the buttons in the AddHobbieView let me go back to the AddUserView.
You add #Environment(\.presentationMode) var presentationMode to AddHobbieView and call self.presentationMode.wrappedValue.dismiss() when you want to dismiss the view
I hope this helps!
I don't want my Login Page and main page show navigationBar, but i need Navigation in RegistrationPage and forgetPasswordPage. I use .navigationBarHidden(self.isNavigationBarHidden) to control my navigationBar.
The mainPage with a tabView and there are some tabItemView with their own NavigationView.
It seemed that my app with a block on the top. When I jump to a sheet and go back to main page, the blank was disappear.
Here is the video for my issue.
https://youtu.be/rIZ3Awzpe3Y
struct LoginView: View {
#EnvironmentObject var userToken: UserToken
#State var account : String = ""
#State var password : String = ""
#State var hint : String = ""
#State var successLogin : Bool = false
#State var hideLoginNavigationBar : Bool = false
#State private var isNavigationBarHidden = true
var body: some View {
NavigationView {
NavigationLink(destination: ResetPassword(isNavigationBarHidden: self.$isNavigationBarHidden)) {
LoginButtonTextStyle(TextValue:"Resetpassword")
}
Button(action: LoginCheck) {
// log in logic
NavigationLink(destination: MainView(isNavigationBarHidden: self.$isNavigationBarHidden), isActive: $successLogin) {
EmptyView()
}
LoginButtonTextStyle(TextValue:"Login")
}
NavigationLink(destination: RegistrationView(isNavigationBarHidden: self.$isNavigationBarHidden)) {
LoginButtonTextStyle(TextValue:"Registration")
}
}.padding(EdgeInsets(top: 0, leading: 50, bottom: 0, trailing: 50))
}
.navigationBarTitle("Login",displayMode: .inline)
.navigationBarHidden(self.isNavigationBarHidden)
.onAppear {
self.isNavigationBarHidden = true
}
}
}
Here is my main page
struct MainView: View {
#State var selectedtab:Int = 1
#Binding var isNavigationBarHidden : Bool
var body: some View {
TabView (selection: $selectedtab){
UserInformationView()
.tabItem {
Image(systemName: "person.fill")
}.tag(0)
.navigationBarTitle("Main")
.navigationBarHidden(true)
TeamListView()
.tabItem {
Image(systemName: "person.3.fill")
}.tag(1)
.navigationBarTitle("Main")
.navigationBarHidden(true)
NotificationView()
.tabItem {
Image(systemName: "bell.fill")
}.tag(2)
.navigationBarTitle("Main")
.navigationBarHidden(true)
SettingView()
.tabItem {
Image(systemName: "list.bullet")
}.tag(3)
.navigationBarTitle("Main")
.navigationBarHidden(true)
}
.navigationBarTitle("Main")
.onAppear(perform: {
self.isNavigationBarHidden = true
})
}
}
one of my tab item view with NavigationView
struct TeamListView: View {
var tutors: [Tutor] = teamData
// var teams: [Team]?
#Environment(\.presentationMode) var presentationMode
#EnvironmentObject var userToken : UserToken
#State var showingDelete = false
#State var teamListFloatingButtonShow = false
#State var goToCreateTeam = false
#State var goToInputInvitionCode = false
#State var addMenuIsPresented: Bool = false
#State var creatTeamIsPresented: Bool = false
#State var teamResults : [TeamResult] = []
var body: some View {
NavigationView {
.....
}
.onAppear(perform: getTeamData)
}