SwiftUI NavigationLink 立即加载目标视图,无需单击

Viv*_*ive 54 ios swift swiftui

使用以下代码:

struct HomeView: View {
    var body: some View {
        NavigationView {
            List(dataTypes) { dataType in
                NavigationLink(destination: AnotherView()) {
                    HomeViewRow(dataType: dataType)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,当HomeView出现时,NavigationLink立即加载AnotherView. 结果,所有AnotherView依赖项也被加载,即使它在屏幕上还不可见。用户必须单击该行才能使其出现。MyAnotherView包含一个DataSource,在那里发生各种事情。问题是此时DataSource已加载整体,包括一些计时器等。

难道我做错了什么..?如何以这种方式处理它,AnotherView一旦用户按下它就会加载HomeViewRow

Mwc*_*Mac 86

我发现解决这个问题的最好方法是使用惰性视图。

struct NavigationLazyView<Content: View>: View {
    let build: () -> Content
    init(_ build: @autoclosure @escaping () -> Content) {
        self.build = build
    }
    var body: Content {
        build()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后 NavigationLink 将如下所示。您可以将要显示的视图放在里面()

NavigationLink(destination: NavigationLazyView(DetailView(data: DataModel))) { Text("Item") }
Run Code Online (Sandbox Code Playgroud)

  • @Ron:“查阅文档”非常模糊,对于那些不知道到底要查找什么的人来说并没有真正的帮助。 (7认同)
  • 这解决了我的所有嵌套视图模型(及其存储库的 api 调用)过早初始化的问题。 (5认同)
  • 很好的解决方案!为了方便起见,我如何将其包装为“LazyNavigationLink”?例如,只需调用 `LazyNavigationLink(DetailView(data: ...` (4认同)
  • 谢谢!我觉得很奇怪,这不是 NavigationLink 的默认行为。给我带来了很多问题! (3认同)
  • 永远不要这样做。这可能会破坏身份并使视图更新效率非常低。查阅文档! (2认同)
  • 我使用了这个解决方案,它的效果就像一个魅力,太棒了!有人可以指出我的方向,以便我了解这里发生了什么吗?另外,为什么罗恩如此反对?对我来说效果很好,解决了很多问题 (2认同)

Fab*_*ian 9

编辑:请参阅@MwcsMac 的答案以获得更简洁的解决方案,该解决方案将视图创建包装在一个闭包中,并且仅在视图呈现后才对其进行初始化。

ForEach由于函数构建器确实必须评估表达式,因此需要自定义来执行您的要求

NavigationLink(destination: AnotherView()) {
    HomeViewRow(dataType: dataType)
}
Run Code Online (Sandbox Code Playgroud)

为了能够显示每个可见行HomeViewRow(dataType:),在这种情况下也AnotherView()必须初始化。

所以为了避免这种情况,一个习惯ForEach是必要的。

import SwiftUI

struct LoadLaterView: View {
    var body: some View {
        HomeView()
    }
}

struct DataType: Identifiable {
    let id = UUID()
    var i: Int
}

struct ForEachLazyNavigationLink<Data: RandomAccessCollection, Content: View, Destination: View>: View where Data.Element: Identifiable {
    var data: Data
    var destination: (Data.Element) -> (Destination)
    var content: (Data.Element) -> (Content)
    
    @State var selected: Data.Element? = nil
    @State var active: Bool = false
    
    var body: some View {
        VStack{
            NavigationLink(destination: {
                VStack{
                    if self.selected != nil {
                        self.destination(self.selected!)
                    } else {
                        EmptyView()
                    }
                }
            }(), isActive: $active){
                Text("Hidden navigation link")
                    .background(Color.orange)
                    .hidden()
            }
            List{
                ForEach(data) { (element: Data.Element) in
                    Button(action: {
                        self.selected = element
                        self.active = true
                    }) { self.content(element) }
                }
            }
        }
    }
}

struct HomeView: View {
    @State var dataTypes: [DataType] = {
        return (0...99).map{
            return DataType(i: $0)
        }
    }()
    
    var body: some View {
        NavigationView{
            ForEachLazyNavigationLink(data: dataTypes, destination: {
                return AnotherView(i: $0.i)
            }, content: {
                return HomeViewRow(dataType: $0)
            })
        }
    }
}

struct HomeViewRow: View {
    var dataType: DataType
    
    var body: some View {
        Text("Home View \(dataType.i)")
    }
}

struct AnotherView: View {
    init(i: Int) {
        print("Init AnotherView \(i.description)")
        self.i = i
    }
    
    var i: Int
    var body: some View {
        print("Loading AnotherView \(i.description)")
        return Text("hello \(i.description)").onAppear {
            print("onAppear AnotherView \(self.i.description)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)