How to hide NavigationBar when the view disappears in SwiftUI? - ios

struct SomeView: View {
var body: some View {
ZStack {
//rest of the code goes here
}.navigationBarTitle("Some View")
}
}
I am trying to hide my view's NavigationBar using .onDisappear{} but it doesn't work and throws a warning. How can I hide my NavigationBar when the view disappears or some condition returns true but not otherwise?

Hide navigation bar view - navigationBarHidden option
struct SomeView: View {
#State private var condition = false
var body: some View {
NavigationView {
Toggle(isOn: $condition) {
Text("Hide NavigationBar View")
}.padding(.horizontal)
.navigationBarTitle("Some View")
.navigationBarHidden(condition)
}
}
}

Related

Present modal view on navigation to another view in swiftui

Let me know if this is a duplicate question.
I am developing an app with a photo picker. I am on view A and there is a + button on it. When I tap on the +, I want to navigate to a view B. Upon navigation I want to present a Photo Picker view automatically inside view B. I am not able to figure out how to do that presentation of the sheet in Swiftui.
In UIKit,on the viewdidappear of viewcontroller B, i would present the Pickerview.
Here's the code that I have
```import SwiftUI
struct ViewB: View {
#State private var showingImagePicker = false
#State private var uploadedPhotos = [UIImage]()
var body: some View {
VStack {
Button("Select Image") {
showingImagePicker = true
}
}
.sheet(isPresented: $showingImagePicker) {
PhotoPicker(photoList: $uploadedPhotos)
}
.onChange(of: uploadedPhotos) { _ in
}
}
}```
This code is ViewB and I will present the pickerView on tapping a button in viewB. but I don't want to tap on button but instead want the picker to show up on appear of ViewB
There is a view modifier in SwiftUI known as .onAppear(perform:), which is the SwiftUI counterpart to UIKit's viewDidAppear and gives you an entry point upon the construction and display of a SwiftUI view. Simply add this modifier to View B (the view inside the sheet that you are presenting). In the closure that you provide to the modifier, you can change the state to present the picker as needed.
If you'd like the picker view to animate in after the view appears, the appropriate place to declare the transition and animation context is on the view acting as your picker view.
struct ViewB: View {
#State private var displayPicker = false
var body: some View {
VStack {
Text("This is View B")
if displayPicker {
PickerView()
.transition(.slide)
.animation(.easeInOut, value: displayPicker)
}
}
.onAppear {
displayPicker = true
}
}
}
Read more about the modifier here:
https://developer.apple.com/documentation/SwiftUI/AnyView/onAppear(perform:)
Think I figured it out -
struct CreateView: View {
#State private var image: Image?
#State private var showingImagePicker = false
#State private var uploadedPhotos = [UIImage]()
var body: some View {
ScrollView {
HStack {
image?.resizable().scaledToFit()
}
.onAppear {
showingImagePicker = true
}
.sheet(isPresented: $showingImagePicker) {
PhotoPicker(photoList: $uploadedPhotos)
}
.onChange(of: uploadedPhotos) { _ in
guard let uiImage = uploadedPhotos.first else {return}
image = Image(uiImage: uiImage)
}
}
}
}
Here PhotoPicker() is the customview that I have

SwiftUI can't hide navigationBar on pushed view when previous view search bar active

I have a problem when pushing to a new view with a search bar active.
In the pushed view I want the navigation bar to be hidden. It works in all cases except when the search field is active on the pushing view AND the navigation style is StackNavigationViewStyle.
In the example project below if you select a row, the new view is pushed and the navigation bar is hidden as expected. However, if you first select the search bar to make it active and then press a row, the navigation bar is no longer hidden on the pushed view.
Removing the StackNavigationViewStyle, everything will work fine however I need to have StackNavigationViewStyle.
struct ContentView: View {
#State var searchString = ""
var body: some View {
NavigationView {
List {
NavigationLink {
PushedView()
} label: {
Text("Press Me")
}
}
.listStyle(PlainListStyle())
.searchable(text: $searchString)
.navigationTitle("First View")
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct PushedView: View {
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
Button {
self.presentationMode.wrappedValue.dismiss()
} label: {
Text("Pop View")
}
.navigationTitle("Second View")
.navigationBarHidden(true)
}
}
This might be a solution for now:
import SwiftUI
struct ContentView: View {
#State var searchString = ""
#FocusState private var focusedField: Bool
#State private var isHidden: Bool = false
var body: some View {
NavigationView {
List {
NavigationLink { PushedView(isHidden: $isHidden).onAppear { isHidden = true}.onDisappear {
isHidden = false
} } label: { Text("Press Me") }
}
.navigationTitle("First View")
.searchable(text: $searchString)
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct PushedView: View {
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
#Binding var isHidden: Bool
var body: some View {
Button {
self.presentationMode.wrappedValue.dismiss()
} label: {
Text("Pop View")
}
.navigationTitle("Second View")
.navigationBarHidden(isHidden)
}
}

SwiftUI Show navigation bar title on the back button but not in the previous View

I have two views, one leads to the other. I want that the second view uses the title of the first view for the back button, which should then be: "<View1".
I don't want to show the title in the first view.
Problem: I can't hide navigation bar because it will also hide a custom button which is within it. Setting .navigationTitle("") hides the title in the first view, but also hides it from the back button in the second view.
What I have now:
What I would like to have:
Code:
struct ContentView: View {
#State var isLinkActive = false
var body: some View {
NavigationView {
VStack {
NavigationLink("go to the second view", destination: SecondView(), isActive: $isLinkActive).navigationTitle("View1")
.navigationBarItems(leading: Button(action: {
()
}, label: {
Text("custom button")
}))
}
}.navigationViewStyle(StackNavigationViewStyle())
}
private func btnPressed() {
isLinkActive = true
}
}
struct SecondView: View {
var body: some View {
Color.blue
}
}
You need to create custom back button for destination view as well,and you shouldn’t set navigation title for navigationLink, that’s why you are not able to hide “View1” correctly.
Check below code.
import SwiftUI
struct Test: View {
#State var isLinkActive = false
var body: some View {
NavigationView {
VStack {
NavigationLink("go to the second view", destination: SecondView()
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: Button(action: {
isLinkActive = false
}, label: {
HStack{
Image(systemName: "backward.frame.fill")
Text("View1")
}
})) ,
isActive: $isLinkActive)
}.navigationBarItems(leading: Button(action: {
()
}, label: {
Text("custom button")
}))
}.navigationViewStyle(StackNavigationViewStyle())
}
private func btnPressed() {
isLinkActive = true
}
}
struct SecondView: View {
var body: some View {
Color.blue
}
}
You can try and make navigationBar code as reusable component, because you might need to do this at multiple places.
Output-:
I achieved this by using two modifiers on my main view. Similar to your case, I didn't want a title on the first view, but I wanted the back button on the pushed view to read < Home, not < Back.
.navigationTitle("Home")
.toolbar {
ToolbarItem(placement: .principal) {
Text("")
}
}

SwiftUI: How to make a hidden UITabBar display correctly on View appearing?

I have a TabView, with one of the tabs being a NavigationView. I want the tab bar to be hidden on the navigation destination view. I have achieved this, but the view only appears properly after the first rotation. How do I get it to appear properly the first time (2nd image)?
struct ContentView: View {
var rowIndexes : [Int] = [0,1,2,3,4,5,6]
var body: some View {
TabView {
NavigationView {
List {
ForEach(self.rowIndexes, id: \.self) {i in
NavigationLink(
destination: Color(.blue)
.onAppear(perform: {
Global.tabBar!.isHidden = true
})
.onDisappear(perform: {
Global.tabBar!.isHidden = false
})
) {
Text("\(i)")
}
}
}
}.tabItem {
Image(systemName: "list.number")
Text("List View")
}
NavigationView {
Text("Options View")
}.tabItem {
Image(systemName: "wrench")
Text("Options")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct Global {
static var tabBar : UITabBar?
}
extension UITabBar {
override open func didMoveToSuperview() {
super.didMoveToSuperview()
Global.tabBar = self
print("Tab Bar moved to superview")
}
}
Here's what the screen looks like after clicking on a link in the list for the first time (INCORRECT, with gap at the bottom where the tab bar would be if it wasn't hidden):
Here's what the screen looks like after rotating it to landscape, then back to portrait (CORRECT, blue View extending all the way to the bottom):
Is there a way to force the redraw, or simulate a rotation and back? I have tried various #State, #EnvironmentObect, and #ObservedObject solutions, but none work.
Adding ignore bottom safe area gives behaviour as you want.
NavigationLink(
destination: Color(.blue).edgesIgnoringSafeArea(.bottom) // << here !!
.onAppear(perform: {
MyGlobal.tabBar!.isHidden = true
Tested with Xcode 11.4 / iOS 13.4.

SwiftUI: Hide Navigation Bar on Specific Screens

It seems as though I'm unable to choose which pages I want to hide the Navigation Bar on in swift UI.
I have the following screens:
Main
struct Main: View {
var body: some View {
NavigationView {
Home()
}
}
}
Home
struct Home: View {
var body: some View {
NavigationLink(destination: Details()) {
Text("Go Next")
}
// I expect the navigation bar to show up here, and it does
.navigationBarTitle("Home")
.navigationBarHidden(false)
}
}
Details
struct Details: View {
#Environment(\.presentationMode) var mode: Binding<PresentationMode>
var body: some View {
Button(action: { self.mode.wrappedValue.dismiss() }) {
Text("Go Back")
}
// I expect the navigation bar to be hidden here
// At first, it is hidden. Then, after a second, it pops up
// with the title "Details"
.navigationBarTitle("Details")
.navigationBarHidden(true)
}
}
Either I'm doing this wrong (likely), or Apple has some work to do (also likely).
As I saw earlier, something comes wrong, when you use both:
.navigationBarTitle("some text")
.navigationBarHidden(true)
in code below there is no navigation bar staff and nothing pops up:
struct Details: View {
#Environment(\.presentationMode) var mode: Binding<PresentationMode>
var body: some View {
Button(action: { self.mode.wrappedValue.dismiss() }) {
Text("Go Back")
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true) // even no back button
}
}

Resources