【问题标题】:Nested NavigationLinks with `isActive=true` are not displaying correctly带有 `isActive=true` 的嵌套 NavigationLinks 未正确显示
【发布时间】:2021-09-22 16:57:35
【问题描述】:

我已经开始学习 SwiftUI,但是在构建 NavigationView 时遇到了一些问题 - 我不确定这是否是一个错误,或者我是否误解了嵌套导航链接的工作原理!

这是我当前的代码:

import SwiftUI

struct ContentView: View {
  var body: some View {
    NavigationView {
      ViewOne()
    }
  }
}

struct ViewOne: View {
  @State var isActiveOne: Bool = true

  var body: some View {
    VStack {
      Text("View One")
      
      NavigationLink(
        destination: ViewTwo(),
        isActive: $isActiveOne,
        label: { EmptyView() }
      )
      
      Button(
        action: { self.isActiveOne = true },
        label: { Text("Set isActiveOne=true") }
      )
    }
  }
}

struct ViewTwo: View {
  @State var isActiveTwo: Bool = true

  var body: some View {
    VStack {
      Text("View Two")
      
      NavigationLink(
        destination: Text("Success!"),
        isActive: $isActiveTwo,
        label: { EmptyView() }
      )

      Button(
        action: { self.isActiveTwo = true },
        label: { Text("Set isActiveTwo=true") }
      )
    }
  }
}

struct ContentView_Preview: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

我希望:

  • NavigationView 显示 ViewOne
  • ViewOne 具有 isActiveOne == true,因此会显示第一个 NavigationLink 目标(显示 ViewTwo)
  • ViewTwo 具有 isActiveTwo == true,因此会显示第二个 NavigationLink 目标(显示“成功!”)

但是,当我在 iOS 14.5 模拟器上运行此代码时,第二个 NavigationLink 不会自动显示(我只看到 ViewTwo Button 文本)。

我还觉得奇怪的是,如果我默认 isActiveTrue 为 false,然后按下按钮,它会正确导航 - 默认“true”状态 + 嵌套导航链接的组合似乎是导致问题的原因。

知道这是否是 SwiftUI 中的错误?还是我在这里的设置做错了什么?

任何想法都会是一个巨大的帮助 - 我已经把头撞在墙上一段时间了......

【问题讨论】:

    标签: swift swiftui navigation


    【解决方案1】:

    这看起来像一个错误,你可以在https://feedbackassistant.apple.com提交它

    临时解决方法是将您的NavigationLinks 放入列表中。这似乎适用于 iOS 14.5 和 15(beta 2)

    不可见列表

    如果您不想要列表的行为/外观,那么您可以将列表放在背景上并使其透明(使用 opacity 修饰符)

    以下是不可见列表解决方法的示例:

    struct WorkaroundLink<Destination: View>: View {
        let destination: Destination
        let isActive: Binding<Bool>
    
        var body: some View {
            List {
                NavigationLink(
                    destination: destination,
                    isActive: isActive,
                    label: { EmptyView() }
                )
            }.opacity(0.01)
        }
    }
    
    extension View {
        func workaroundLink<D: View>(to destination: D, isActive: Binding<Bool>) -> some View {
            background(WorkaroundLink(destination: destination, isActive: isActive))
        }
    }
    

    用这个结构重写你的例子变成:

    struct ContentView: View {
        var body: some View {
            NavigationView { ViewOne() }
        }
    }
    
    struct ViewOne: View {
        @State var isActiveOne = true
    
        var body: some View {
            VStack {
                Text("View One")
                Button("Set isActiveOne=true") { isActiveOne = true }
            }.workaroundLink(to: ViewTwo(), isActive: $isActiveOne)
        }
    }
    
    struct ViewTwo: View {
        @State var isActiveTwo = true
        var body: some View {
            VStack {
                Text("View Two")
    
                Button(
                    action: { self.isActiveTwo = true },
                    label: { Text("Set isActiveTwo=true") }
                )
            }.workaroundLink(to: Text("Success!"), isActive: $isActiveTwo)
        }
    }
    

    【讨论】:

    • 感谢达米安的推荐!我已经通过反馈助手 [FB9321916] 提交了一个错误。不幸的是,列表似乎不适用于我的情况(除非有某种方法可以完全隐藏它?) - 我希望以编程方式管理所有路由......我会花一些时间调查,看看是否有一些我的情况的其他解决方法。谢谢!
    • 是的,有一种(有点笨拙的)方法可以(几乎)完全隐藏列表。请参阅我的更新答案。
    • 啊 - 创造性的解决方法!感谢您返回并添加更新的示例 - 非常感谢! :)
    猜你喜欢
    • 2019-07-25
    • 1970-01-01
    • 2013-06-05
    • 2020-12-22
    • 2021-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多