Overview:
On macOS when using NavigationLink, the source view is appearing twice.
It only happens on macOS (see print statements)
Questions:
How to resolve this?
Is there a workaround?
Code:
import SwiftUI
struct ContentView: View {
let names = ["aaa"]
var body: some View {
NavigationView {
List {
ForEach(names, id: \.self) { name in
NavigationLink(destination: Text("dest")) {
Text(name)
.onAppear {
print("\(name) appeared")
}
}
}
}
}
}
}
To resolve this, simply "attach" the .onAppear to your NavigationLink not the Text.
EDIT-1:
This is the test code I'm using to show that moving the .onAppear to the
NavigationLink as shown, prints only one on appear.
I'm using macos 12, Xcode 13.2, tested on iMac with macos 12.2.
import SwiftUI
#main
struct MacOnlyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
let names = ["aaa"]
var body: some View {
NavigationView {
List {
ForEach(names, id: \.self) { name in
NavigationLink(destination: Text("dest")) {
Text(name)
}
.onAppear {
print("----> \(name) appeared \n")
}
}
}
}
}
}
Related
Im trying to show another view with SwiftUI, when a button is pressed. Here is what I am trying:
import SwiftUI
struct Home: View {
var body: some View {
VStack {
Text(/*#START_MENU_TOKEN#*/"Hello, World!"/*#END_MENU_TOKEN#*/)
Button("Press here!") {
iPhone13About()
}
}
}
}
Where I hover over iPhone13About(), it says, "Result of 'iPhone13About' initializer is unused". Im a beginner with Xcode, and I am trying to mess around with Xcode and to create something.
The Swift UI View is called iPhone13.swift, and the function it is passing is
struct iPhone13About: View {
Thanks in advance!
try this.
struct iPhone13About: View {
#Environment(\.dismiss) var dismiss
var body: some View {
Button("Press to dismiss") {
dismiss()
}
.font(.title)
.padding()
.background(Color.black)
}
}
struct HomeView: View {
#State private var iPhone13Flag = false
var body: some View {
Button("iPhone13About") {
iPhone13Flag.toggle()
}
.sheet(isPresented: $showingSheet) {
SheetView()
}
}
}
I understand its new, but this seems like pretty basic functionality that is not here. When implementing a .searchable in the new iOS 15, it would seem that a NavigationLink does not work, at all.
Ideally, the searchable would produce a filtered list with a ForEach and for each item, a Nav Link could take you to another view based on your selection. The ForEach and list works and looks beautiful, it just wont take you anywhere.
Watching WWDC21, they talk an awful lot about .searchable, but very little demonstration/example is given..
Here is a simple example, with no ForEach loop, that shows it does not work at all.. Am I missing something?
Any insight appreciated:
import SwiftUI
struct ContentView: View {
#State private var term = ""
var body: some View {
NavigationView {
Text("Hello, world!")
.padding()
}
.searchable(text: $term) {
NavigationLink(destination: SecondView()) {
Text("Go to second view")
}
}
}
}
struct SecondView: View {
var body: some View {
Text("Goodbye!")
.padding()
}
}
NavigationLink must always be inside NavigationView, no matter what. If you want to put it outside, like inside .searchable, you should use programmatic navigation with isActive.
struct ContentView: View {
#State private var term = ""
#State private var isPresenting = false
var body: some View {
NavigationView {
/// NavigationView must only contain 1 view
VStack {
Text("Hello, world!")
.padding()
/// invisible NavigationLink
NavigationLink(destination: SecondView(), isActive: $isPresenting) { EmptyView()}
}
}
.searchable(text: $term) {
Button { isPresenting = true } label: {
Text("Go to second view")
}
}
}
}
struct SecondView: View {
var body: some View {
Text("Goodbye!")
.padding()
}
}
Result:
I have a watchOS App which uses the following layout:
NavigationView {
if !HKHealthStore.isHealthDataAvailable() {
ContentNeedHealthKitView()
} else if !isAuthorized {
ContentUnauthorizedView()
} else {
TabView(selection: $selection) {
WeightView()
.navigationTitle("Weight")
.tag(1)
.onAppear {
print("Appear!")
}
.onDisappear {
print("Disappear!")
}
SettingsView()
.navigationTitle("Settings")
.tag(2)
}
}
}
Unfortunately, the OnAppear and OnDisappear actions are only executed after transitioning from on view to another the second time. When swiping right the first time, nothing happens.
You should provide a minimal reproducible example (see https://stackoverflow.com/help/minimal-reproducible-example).
Also your lines are producing compiler errors. The correct way to use onAppear is like this:
.onAppear {
}
Here is a working example, everything is working as expected. You should also place the onAppear ViewModifier to the child view.
import SwiftUI
struct WeightView: View {
var body: some View {
Text("WeightView")
.onAppear {
print("Appear!")
}
.onDisappear {
print("Disappear!")
}
}
}
struct SettingsView: View {
var body: some View {
Text("SettingsView")
}
}
struct ContentView: View {
#State var selection = 1
#State var isAuthorized = false
var body: some View {
NavigationView {
if !isAuthorized {
Button("authorize") {
isAuthorized.toggle()
}
} else {
TabView(selection: $selection) {
WeightView()
.navigationTitle("Weight")
.tag(1)
SettingsView()
.navigationTitle("Settings")
.tag(2)
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I started to use SwiftUI after a couple years of UIKit.. This is not a piece of cake lol.
Alright, so I am trying to build an app that has a tab bar with 2 elements. Each Tab with contain a ViewController (View now) and they will be embedded in a NavigationController (NavigationView now)
The actual result is this
and I am expecting to have a nav bar with a title set to Home.
Could you explain me what I do wrong here? i followed the documentation and a couple tutorials, and I don't seem to do differently.
import SwiftUI
struct TabBarView: View {
var body: some View {
TabView() {
RedView()
.tabItem({
Image(systemName: "house.fill")
Text("Home")
})
.tag(0)
BlueView()
.tabItem({
Image(systemName: "dollarsign.square.fill")
Text("Trade")
})
.tag(1)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
TabBarView()
}
}
struct RedView: View {
var body: some View {
NavigationView {
List {
Text("test")
}
}
.navigationBarTitle("Home")
}
}
struct BlueView: View {
var body: some View {
NavigationView {
List {
Text("test2")
}
}
.navigationBarTitle("Trade")
}
}
This is the file that contains everything at the moment. Thanks in advance for any future help!
The .navigationBarTitle should be inside NavigationView
struct RedView: View {
var body: some View {
NavigationView {
List {
Text("test")
}
.navigationBarTitle("Home") // << here !!
}
}
}
UPDATE: Resolved - This topic is just a beta bug.
I'm having a problem with the navigationBarTitle in SwiftUI.
I'm using a NavigationLink to go to a second view with a list. This view has a navigationBarTitle like the first view. But in the second view I can push the list behind the navigationBarTitle.
When I'm going from a third view back to the second the navigationBarTitle works as it should be.
Does anyone else having this problem? I'm using Xcode Version 11.0 GM (11A419c)
Here is the code:
struct ContentView: View {
private var line : [String] = ["Line 1", "Line 2", "Line 3"]
var body: some View {
NavigationView {
List {
ForEach(line, id: \.self) { item in
NavigationLink(destination: DetailView()) {
TestCell(lineName: item)
}
}
}
.navigationBarTitle("Main View")
}
}
}
struct TestCell: View {
let lineName: String
var body: some View {
Text(lineName)
}
}
struct DetailView: View {
var body: some View {
List() {
NavigationLink(destination: DetailDetailView()) {
Text("To the next view")
.foregroundColor(Color.red)
}
}
.navigationBarTitle("Detail View")
}
}
struct DetailDetailView: View {
var body: some View {
Text("Hello World!")
.navigationBarTitle("Detail Detail View")
}
}