SwiftUI NavigationLink 自己弹出
SwiftUI NavigationLink pops out by itself
我有一个简单的用例,其中一个屏幕使用 NavigationLink
推送另一个屏幕。 iOS 14.5 beta (1, 2, 3) 有一个奇怪的行为,推送的屏幕刚被推送就弹出。
我设法创建了一个示例应用程序并在其中复制它。我相信原因是 @Environment(\.presentationMode)
的存在似乎重新创建了视图,它导致推送的视图被弹出。
完全相同的鳕鱼在 Xcode 12 / iOS 14.4
中工作正常
这是示例代码。
import SwiftUI
public struct FirstScreen: View {
public init() {}
public var body: some View {
NavigationView {
List {
row
row
row
}
}
}
private var row: some View {
NavigationLink(destination: SecondScreen()) {
Text("Row")
}
}
}
struct SecondScreen: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
public var body: some View {
VStack(spacing: 10) {
NavigationLink(destination: thirdScreenA) {
Text("Link to Third Screen A")
}
NavigationLink(destination: thirdScreenB) {
Text("Link to Third Screen B")
}
Button("Go back", action: { presentationMode.wrappedValue.dismiss() })
}
}
var thirdScreenA: some View {
Text("thirdScreenA")
}
var thirdScreenB: some View {
Text("thirdScreenB")
}
}
struct FirstScreen_Previews: PreviewProvider {
static var previews: some View {
FirstScreen()
}
}
恰好有 2 个 NavigationLinks 时看起来像是一个错误。
如果您添加另一个空的 link 它就会消失:
NavigationLink(destination: EmptyView(), label: {})
更多详情:https://forums.swift.org/t/14-5-beta3-navigationlink-unexpected-pop/45279
我刚刚添加了 .navigationViewStyle(StackNavigationViewStyle())
& bug 消失了
示例:--
NavigationView {
content
}
.navigationViewStyle(StackNavigationViewStyle())
就我而言,我有:
(1) 具有 2 个导航起点的根视图的选项卡视图
(2)第一个和第二个导航有相当多的嵌套视图
(3) 添加 .navigationViewStyle(StackNavigationViewStyle() 只解决了只有一个导航起点的根视图的问题
(4) 当我有来自同一视图的另一个导航时,问题再次出现(仅适用于 iOS 14.5 至 14.8)
(5) 仅添加
NavigationLink(destination: EmptyView()) {
EmptyView()
}
不适合我
(6) 在我的项目中,我有一个协调员负责创建 viewModel(已发布的属性),并且我有一个 ContainerView 将处理所有导航。导航 link 是基于 viewModel 是否存在而创建的,因此如果 viewModel 存在,则该视图将被呈现,当视图被关闭时,viewModel 将被设置为 nil。 (我会在最后添加执行此操作的代码)
(7) 由于某些奇怪的原因,向负责导航的视图添加第三个导航停止了我的容器视图的重新渲染和视图停止弹出。
简单地将 NavigationLink 添加到容器中不起作用,但使用我正在使用的修饰符并将目的地设置为空 NavigationLink 就可以了。
这是用于导航的代码:
func navigation<Item, Destination: View>(
item: Binding<Item?>,
@ViewBuilder destination: (Item) -> Destination
) -> some View {
let isActive = Binding(
get: { item.wrappedValue != nil },
set: { value in
if !value {
item.wrappedValue = nil
}
}
)
return navigation(isActive: isActive) {
item.wrappedValue.map(destination)
}
}
func navigation<Destination: View>(
isActive: Binding<Bool>,
@ViewBuilder destination: () -> Destination
) -> some View {
overlay(
NavigationLink(
destination: isActive.wrappedValue ? destination() : nil,
isActive: isActive,
label: { EmptyView() }
)
)
}
我的容器视图就是这样工作的。我的协调器具有作为可选 viewModel 的 Published 属性,该 viewModel 的存在与否是触发导航 link 上的 isActive 值的原因。添加最后一个 .navigation 有效。我的空容器只有空的 navigationLink
将 .isDetailLink(false)
应用到您的 NavigationLink 可能会完成这项工作。默认情况下为真。来自文档:
This method sets the behavior when the navigation link is used in a
multi-column navigation view, such as DoubleColumnNavigationViewStyle.
If isDetailLink is true, performing the link in the primary column
sets the contents of the secondary (detail) column to be the link’s
destination view. If isDetailLink is false, the link navigates to the
destination view within the primary column.
我有一个简单的用例,其中一个屏幕使用 NavigationLink
推送另一个屏幕。 iOS 14.5 beta (1, 2, 3) 有一个奇怪的行为,推送的屏幕刚被推送就弹出。
我设法创建了一个示例应用程序并在其中复制它。我相信原因是 @Environment(\.presentationMode)
的存在似乎重新创建了视图,它导致推送的视图被弹出。
完全相同的鳕鱼在 Xcode 12 / iOS 14.4
中工作正常这是示例代码。
import SwiftUI
public struct FirstScreen: View {
public init() {}
public var body: some View {
NavigationView {
List {
row
row
row
}
}
}
private var row: some View {
NavigationLink(destination: SecondScreen()) {
Text("Row")
}
}
}
struct SecondScreen: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
public var body: some View {
VStack(spacing: 10) {
NavigationLink(destination: thirdScreenA) {
Text("Link to Third Screen A")
}
NavigationLink(destination: thirdScreenB) {
Text("Link to Third Screen B")
}
Button("Go back", action: { presentationMode.wrappedValue.dismiss() })
}
}
var thirdScreenA: some View {
Text("thirdScreenA")
}
var thirdScreenB: some View {
Text("thirdScreenB")
}
}
struct FirstScreen_Previews: PreviewProvider {
static var previews: some View {
FirstScreen()
}
}
恰好有 2 个 NavigationLinks 时看起来像是一个错误。 如果您添加另一个空的 link 它就会消失:
NavigationLink(destination: EmptyView(), label: {})
更多详情:https://forums.swift.org/t/14-5-beta3-navigationlink-unexpected-pop/45279
我刚刚添加了 .navigationViewStyle(StackNavigationViewStyle())
& bug 消失了
示例:--
NavigationView {
content
}
.navigationViewStyle(StackNavigationViewStyle())
就我而言,我有:
(1) 具有 2 个导航起点的根视图的选项卡视图
(2)第一个和第二个导航有相当多的嵌套视图
(3) 添加 .navigationViewStyle(StackNavigationViewStyle() 只解决了只有一个导航起点的根视图的问题
(4) 当我有来自同一视图的另一个导航时,问题再次出现(仅适用于 iOS 14.5 至 14.8)
(5) 仅添加
NavigationLink(destination: EmptyView()) {
EmptyView()
}
不适合我
(6) 在我的项目中,我有一个协调员负责创建 viewModel(已发布的属性),并且我有一个 ContainerView 将处理所有导航。导航 link 是基于 viewModel 是否存在而创建的,因此如果 viewModel 存在,则该视图将被呈现,当视图被关闭时,viewModel 将被设置为 nil。 (我会在最后添加执行此操作的代码)
(7) 由于某些奇怪的原因,向负责导航的视图添加第三个导航停止了我的容器视图的重新渲染和视图停止弹出。
简单地将 NavigationLink 添加到容器中不起作用,但使用我正在使用的修饰符并将目的地设置为空 NavigationLink 就可以了。
这是用于导航的代码:
func navigation<Item, Destination: View>(
item: Binding<Item?>,
@ViewBuilder destination: (Item) -> Destination
) -> some View {
let isActive = Binding(
get: { item.wrappedValue != nil },
set: { value in
if !value {
item.wrappedValue = nil
}
}
)
return navigation(isActive: isActive) {
item.wrappedValue.map(destination)
}
}
func navigation<Destination: View>(
isActive: Binding<Bool>,
@ViewBuilder destination: () -> Destination
) -> some View {
overlay(
NavigationLink(
destination: isActive.wrappedValue ? destination() : nil,
isActive: isActive,
label: { EmptyView() }
)
)
}
我的容器视图就是这样工作的。我的协调器具有作为可选 viewModel 的 Published 属性,该 viewModel 的存在与否是触发导航 link 上的 isActive 值的原因。添加最后一个 .navigation 有效。我的空容器只有空的 navigationLink
将 .isDetailLink(false)
应用到您的 NavigationLink 可能会完成这项工作。默认情况下为真。来自文档:
This method sets the behavior when the navigation link is used in a multi-column navigation view, such as DoubleColumnNavigationViewStyle. If isDetailLink is true, performing the link in the primary column sets the contents of the secondary (detail) column to be the link’s destination view. If isDetailLink is false, the link navigates to the destination view within the primary column.