I am writing an app using SwiftUI, and I am having some issues with the NavigationView and the Navigation Link, as shown below in the simulator video. The project was created as a Single View App.
I have three pages, and as you can see when it takes me from one page to the other, it builds the second page under the first one, and doesn’t dellocate the first one, and I have the same problem on the third page: it is created below the second one, and I can even go back to the first page via the faulty back button on the top left.
Video:
This is the code of the three pages:
first.swift
import SwiftUI
struct first: View {
var body: some View {
NavigationView{
NavigationLink(destination: second()) {
Text("first link")
}
}
}
}
struct first_Previews: PreviewProvider {
static var previews: some View {
first()
}
}
second.swift
import SwiftUI
struct second: View {
var body: some View {
NavigationView {
NavigationLink(destination: third()) {
Text("second link")
}
}
}
}
struct second_Previews: PreviewProvider {
static var previews: some View {
second()
}
}
third.swift
import SwiftUI
struct third: View {
var body: some View {
Text("Third page")
}
}
struct third_Previews: PreviewProvider {
static var previews: some View {
third()
}
}
I am using the Navigation View in the same manner that the official apple tutorial does (or at least I think I am…) here
Thanks!
Edit: I'm still having the same problem with this code, despite having defined only one NavigationView. The problem came back after I uploaded to Xcode 11.2, but in the Release Notes it doesn't say anything about any changes made to the NavigationView.
first.swift
import SwiftUI
struct first: View {
var body: some View {
NavigationView {
NavigationLink(destination: second()) {
Text("First link")
}
}
}
}
struct first_Previews: PreviewProvider {
static var previews: some View {
first()
}
}
second.swift
import SwiftUI
struct second: View {
var body: some View {
NavigationLink(destination: first()) {
Text("back to first")
}
}
}
struct second_Previews: PreviewProvider {
static var previews: some View {
second()
}
}
Video:
Thanks again!
What your current code is doing is nesting the NavigationView in second inside of the one in first.
To get around this you just need to delete the NavigationView in second:
struct second: View {
var body: some View {
NavigationLink(destination: third()) {
Text("second link")
}
}
}
Related
Since iOS 15, clicking a NavigationLink in a NavigationView sometimes does not dismiss its nested list / sidebar on iPads in portrait orientation. The first click will dismiss the list, then it gets stuck. You can drag / scroll the list up and down to make the auto-hide behavior work again temporarily but it gets stuck again.
Here is some sample code to demonstrate:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(0...30, id: \.self) { n in
NavigationLink(
"\(n)",
destination: DetailView(n: n)
)
}
}
.navigationBarTitle("List")
}
}
}
struct DetailView: View {
var n: Int
var body: some View {
Text("\(n)")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Considering how basic the code above is, my guess is that it's an iOS 15 bug but I would appreciate any pointers if it isn't. Thanks!
I would like to create reusable components in my app.
I have searched for similar problem. But I have only found much more complex examples.
Let's try this simple example - a button that could open different Views based on passed parameter.
I have 2 views that I will open as a sheet:
FirstView.swift
import SwiftUI
struct FirstView: View {
var body: some View {
Text("First view")
}
}
SecondView.swift
struct SecondView: View {
var body: some View {
Text("Second view")
}
}
ButtonView.swift
This is a view I would like to use as a reusable component in my design system.
import SwiftUI
struct ButtonView: View {
#State private var showModal: Bool = false
// This works
var text: String
// Here I am getting an error:
// Protocol 'View' can only be used as a generic constraint because it has Self or associated type requirements
var link: View
var body: some View {
VStack {
Spacer()
Button(action: {
self.showModal = true
}) {
Text(text)
.padding(20)
.foregroundColor(Color.white)
}.sheet(isPresented: self.$showModal) {
link
}
.background(Color.blue)
}
}
}
struct ButtonView_Previews: PreviewProvider {
static var previews: some View {
ButtonView(text: "TEST", link: FirstView())
}
}
ContentView.swift Here I am trying to use the same button component, but with different labels and links.
import SwiftUI
struct ContentView: View {
var body: some View {
HStack {
ButtonView(text: "first", link: FirstView())
.padding()
ButtonView(text: "second", link: SecondView())
.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Passing String parameters works. Labels are different. But I cannot make it work with links to different Views. I am getting an error:
Protocol 'View' can only be used as a generic constraint because it
has Self or associated type requirements
Keeping First view and Second View as the same, use the following for the ButtonView:
struct ButtonView<Content : View>: View {
#State private var showModal: Bool = false
var text: String
// This is the generic content parameter
let content: Content
init(text: String, #ViewBuilder contentBuilder: () -> Content){
self.text = text
self.content = contentBuilder()
}
var body: some View {
VStack {
Spacer()
Button(action: {
self.showModal = true
}) {
Text(text)
.padding(20)
.foregroundColor(Color.white)
}.sheet(isPresented: self.$showModal) {
content
}
.background(Color.blue)
}
}
}
Here the generic parameter named content is used to receive any view and the initializer is used with the #ViewBuilder property wrapper to build the view.Now use it in the following way in ContentView struct:
struct ContentView: View {
var body: some View {
HStack {
ButtonView(text: "First") {
FirstView()
}
ButtonView(text: "Second") {
SecondView()
}
}
}
}
It will work like a charm :)
Also if you want to keep preview for ButtonView and don't want it to crash then add the preview as:
struct ButtonView_Previews: PreviewProvider {
static var previews: some View {
ButtonView(text: "First") {
FirstView()
}
}
}
I'm trying to change my status bar color dynamically without success, anyone has any idea how to change it ?
I'm not using UIHosting controller so there is no AppDelegate or SceneDelegate fully using swiftUI:
#main
struct MyProjectApp: App{}
If i set ZStack {}.preferredColorScheme(.light) it only apply once, so if i go to another view and try to put ZStack {}.preferredColorScheme(.dark) it doesn't work.
I think i have try all the question here on stackoverflow, so if anyone have a definitive solution i appreciated.
#Updated code example
struct ContentA: View {
var body: some View {
NavigationView {
ZStack {
NavigationLink(destination: ContentB()) {
Text("Show Detail View")
}.navigationBarTitle("Navigation")
}.preferredColorScheme(.light)
}
}
}
struct ContentB: View {
var body: some View {
ZStack {
Text("Hello ContetB")
.padding()
.foregroundColor(.green)
}.preferredColorScheme(.dark)
}
}
If you try to change StatusBar color using this way it doesn't work.
The colors within the app should be dynamic automatically, unless you set them specifically. You can toggle the .preferredColorScheme within the Previews section.
struct ContentView: View {
var body: some View {
Text("Hello, world!")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.preferredColorScheme(.dark)
}
}
Is there a way to disable the SplitView using SwiftUI on iPad inside a navigation view?
By setting the NavigationViewStyle
import SwiftUI
struct NavView: View {
var body: some View {
NavigationView{
List{
NavigationLink(destination: TestView(), label: {Text("TestView")})
}
}.navigationViewStyle(StackNavigationViewStyle())
}
}
struct NavView_Previews: PreviewProvider {
static var previews: some View {
NavView()
}
}
I needed to add a view to my scene using a view transition. I was trying to use the modifier .transition(.opacity) but it just adds the view without any transition. I also tried the other transition types and they don't work. Since this is a really simple test project a don't see where's the issue. Here's a link to a video of my problem
import SwiftUI
struct Test: View {
#State var show = false
var body: some View {
VStack {
Button(action: {self.show.toggle()}) {
Text("Button")
}
if show {
Text("Test Text")
.transition(.move(edge: .top))
}
}
}
}
struct Test_Previews: PreviewProvider {
static var previews: some View {
Test()
}
}
You need to add animation for the transition
if show {
Text("Test Text").animation(.linear)
.transition(.move(edge: .top))
}