Why watchOS picker always shows "ScrollView contentOffset binding has been read" warning? - swiftui

Bare minimum picker test app for watchOS.
import SwiftUI
#main
struct PickerTestApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
ContentView()
}
}
}
}
ContentView
import SwiftUI
struct ContentView: View {
var body: some View {
VStack{
NavigationLink(destination: DistanceSelectView()) {
Text("Next screen")
}
}
}
}
DistanceSelectView
import SwiftUI
struct DistanceSelectView: View {
#State var Age = 1
var body: some View {
VStack {
Picker(selection: $Age, label: Text("Select your age.[\(Age)]")) {
ForEach(10 ..< 100, id: \.self) { num in
Text("\(num)")
}
}
}
}
}
When run, and "Next screen" NavigationLink is pressed, it always displays the following warning:
"ScrollView contentOffset binding has been read; this will cause grossly inefficient view performance as the ScrollView's content will be updated whenever its contentOffset changes. Read the contentOffset binding in a view that is not parented between the creator of the binding and the ScrollView to avoid this."
What I'm doing wrong here?

Related

SwiftUI NavigationLink destination in TabView will be dismissed after background scene phase

In the "Dest" view, after my app going to background mode and coming back to foreground mode, the navigation destination is dismissed automatically. How can I prevent this? Here is my code:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
TabView {
NavigationLink {Text("Dest")} label: {Text("go to dest")}.tabItem {Text("c1")}
Text("a2").tabItem {Text("c2")}
}
}
}
}
Put the NavigationView inside the TabView:
var body: some View {
TabView {
NavigationView { // here
NavigationLink() {
Text("Dest")
} label: {
Text("go to dest")
}
}
.tabItem {Text("c1")}
Text("a2")
.tabItem {Text("c2")}
}
}

SwiftUI: NavigationLink pops out immediately on WatchOS 8.1RC in Tabview

I have discovered a regression in watchOS 8.1RC with NavigationLink triggered from a TabView.
It's immediately dismissed.
It was working in watchOS 8.0 or in Simulator (watchOS 8.0).
Do you know a workaround ?
Thanks
Sample code:
import SwiftUI
#main
struct TestNavigationApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
ContentView()
}
}
}
}
struct ContentView: View {
var body: some View {
List {
NavigationLink(destination: ContentView1()) {
Text("To TabView")
}
}
}
}
struct ContentView1: View {
var body: some View {
TabView {
NavigationView {
NavigationLink(destination: ContentView2()) {
Text("To ContentView2")
}
}
VStack {
Text("Screen2")
}
}
}
}
struct ContentView2: View {
var body: some View {
Text("ContentView2")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I'm experiencing the same issue with watchOS 8.1 (and 8.3 beta) while it was working with previous watchOS versions.
We were able to get it working again by moving the NavigationView inside the TabView. This workaround isn't ideal at all but it does seem to work.
#State private var tabSelection = 1
var body: some Scene {
WindowGroup {
TabView(selection: $tabSelection) {
NavigationView {
// List goes here
}
.tag(1)
VStack(alignment: .center, spacing: 12, content: {
// content 2nd tab: we didn't have a list in the 2nd tab
})
.tag(2)
}
}
}
However, there are 2 things impacted with this fix:
I didn't get the navigationBarTitle working, so there won't be a title on top of the screen.
If you click on an item in the list, it will navigate to your page (as expected) but the TabView dots at the bottom of the screen will remain.

SwiftUI list does not scroll using 2-finger swipe on trackpad

I have been testing this simple SwiftUI code: It has a list in ContentView. When a cell of the list is tapped, it pushes a SecondList into the navigation stack. When this SwiftUI code was run on a real iPad with a trackpad, I used 2-finger swipe to scroll the list up and down. The list in ContentView scrolls smoothly. However, for SecondList, it may freeze randomly and thereafter not responding.
It also failed in a UIKit project, where I replaced a UINavigationView with this ContentView using UIHostingViewController.
It was testing it with iPadOS 14.5 on both Simulator and iPad Pro hardware with Magic Keyboard.
How do I fix this? Thank you.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(0..<30, id: \.self) { index in
NavigationLink(
destination: SecondList(),
label: {
Text(String(index))
})
}
}
}.navigationViewStyle(StackNavigationViewStyle())
}
}
struct SecondList: View {
var body: some View {
List {
ForEach(0..<30, id: \.self) { index in
Text(String(index))
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Use a scrollView
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(0..<30, id: \.self) { index in
NavigationLink(
destination: SecondList(),
label: {
Text(String(index))
})
}
}
}.navigationViewStyle(StackNavigationViewStyle())
}
}
struct SecondList: View {
var body: some View {
scrollView {
List {
ForEach(0..<30, id: \.self) { index in
Text(String(index))
}
}
}
}
}

Why is SwiftUI presented view displayed incorrectly?

I've created a SwiftUI "multiplatform" (iOS and macOS) app from the Xcode 12 beta 6 (12A8189n) app template.
My issue is that one of my views, AnotherView, is displaying incorrectly. Here's a gif showing the problem. Notice that AnotherView displays with the navigation stack already pushed to a non-existent view. Tapping the back button reveals the expected screen, however it is displayed only partially filling the expected area.
Here's the code:
TestNavigationApp.swift
import SwiftUI
#main
struct TestNavigationApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
ContentView.swift
import SwiftUI
struct ContentView: View {
#State private var presentingFirstView = false
var body: some View {
Button(action: { self.presentingFirstView = true }) {
Text("Present First View")
}
.sheet(isPresented: $presentingFirstView) {
FirstView(isPresented: $presentingFirstView)
}
}
}
FirstView.swift
import SwiftUI
struct FirstView: View {
#Binding var isPresented: Bool
var body: some View {
NavigationView {
EmbeddedView()
.navigationBarTitle("First View", displayMode: .large)
}
}
}
EmbeddedView.swift
import SwiftUI
struct EmbeddedView: View {
#State private var presentingAnotherView = false
var body: some View {
VStack {
Text("Embedded View")
Button(action: { self.presentingAnotherView = true }) {
Text("Present Another View")
}
}
.sheet(isPresented: $presentingAnotherView) {
AnotherView(isPresented: $presentingAnotherView)
}
}
}
AnotherView.swift
import SwiftUI
struct AnotherView: View {
#Binding var isPresented: Bool
var body: some View {
NavigationView {
Text("Another View")
.navigationBarTitle("Another View", displayMode: .large)
}
}
}
Anyway, not really sure what's happening here. Any suggestions appreciated.
Try to use navigation view style explicitly
var body: some View {
NavigationView {
Text("Another View")
.navigationBarTitle("Another View", displayMode: .large)
}.navigationViewStyle(StackNavigationViewStyle())
}

Multi Level Navigation SwiftUI

I have a master detail application I'm working on in SwiftUI but once on the 1st DetailView, NavigationLink in the NavBar no longer works. I wrote this as a simple demonstration:
struct NavView: View {
var body: some View {
NavigationView {
NavigationLink(destination: Layer()) {Text("Go to Layer 1")}
}
}
}
struct Layer: View {
var body: some View {
Text("Welcome to Layer 1")
.navigationBarItems(trailing: NavigationLink(destination: AnotherLayer()) { Text("Go to Layer 2") })
}
}
struct AnotherLayer: View {
var body: some View {
Text("Welcome to Layer 2")
}
}
Everything renders and you can tap the navigationBarItem in Layer but nothing happens.
What's going on here? How can I access AnotherLayer?
A NavigationLink used as a navigationBarItem will not work no matter if you use it in the first or second level but a NavigationDestinationLink would solve the problem.
import SwiftUI
struct TestSwift: View {
var body: some View {
NavigationView {
NavigationLink(destination: Layer()) {Text("Go to Level")}
}
}
}
struct Layer: View {
let detailView = NavigationDestinationLink(AnotherLayer())
var body: some View {
VStack {
Text("Text")
}
.navigationBarItems(trailing:
Button(action: {
self.detailView.presented?.value = true
}, label: {
Text("Present Now!")
})
)
}
}
struct AnotherLayer: View {
var body: some View {
Text("Hello")
}
}