SwiftUI导航链接和面临的常见陷阱
NavigationLink介绍
每个应用程序都需要导航,当然,除非您制作的杀手级应用程序仅在单个视图上运行良好。NavigationView是负责浏览不同视图的主要参与者之一(另一个是TabView)。NavigationView在SwiftUI类似于UINavigationController在UIKit中。NavigationLink负责将用户带到destination如下所示的指定视图中:
NavigationLink(destination: Text("New Screen")) {
Text("Press me")
}
NavigationLink的body是个view视图,当按下该视图时,会将用户带到目标视图。
要NavigationLink使它正常工作,它必须是的一部分NavigationView,尽管没有明确规定。
本文目标
- 了解导航的不同方式。
- 处理NavigationLink会掩盖其中的视图。
- 处理NavigationLink不会延迟加载的目标。
一点历史
自SwiftUI发布以来,导航链接已经发生了许多更改和弃用。
之类的东西DynamicNavigationDestinationLink,NavigationDestinationLink和NavigationButton已被取消,现在包括它们的功能中NavigationLink(在写作的时候)。
以编程方式导航
通常,需要根据某些异步事件或条件来触发导航链接。对于这种情况,我们可以将导航链接设置为以编程方式触发,如下所示:
NavigationView{
VStack{
NavigationLink(destination: Text("New Screen"), isActive: self.$isActive) {
Text("")
}
Button("Press programmatically"){
self.isActive = true
}
}
}
在上面的代码中,使用NavigationLink定义了isActive,false最初设置为。
按下按钮后,state属性将设置为true,从而body再次呈现SwiftUI视图的,从而触发NavigationLink现在处于活动状态的。
路由带有标签的NavigationLink
在存在多个导航链接的情况下,采用上述方法路由到导航链接将需要太多状态变量。
幸运的是,NavigationLink通过使用标签提供了另一种实现,如下所示:
@State var selection : Int? = nil
var body: some View {
NavigationView{
VStack{
NavigationLink(destination: Text("New Screen"), tag: 1, selection: self.$selection) {
Text("")
}
NavigationLink(destination: Text("New Screen 2"), tag: 2, selection: self.$selection) {
Text("")
}
Button("Button 1"){
self.selection = 1
}
Button("Button 2"){
self.selection = 2
}
}
}
}
带有列表的NavigationLink
NavigationLinks,即使看起来不方便,但如果处理不当,也很容易失控。
现在,我们已经讨论了不同的设置方法NavigationLinks,现在是时候解决将组件集成到SwiftUI应用程序时遇到的常见陷阱。
陷阱1. NavigationLink在ScrollView下遮罩视图
要删除此叠加层,只需将的buttonStyle属性设置NavigationLink为,如下所示:
NavigationLink(destination: Text("Detail Screen")){
Image("car")
.background(Color.red)
}.buttonStyle(PlainButtonStyle())
在另一种情况下,如果我们在导航视图中使用PickerView而不是Lists,则将buttonStyle其设置为纯色将导致图像的蒙版,如本段所示。
因此,在这些情况下,将Image渲染模式设置为十分重要original。
陷阱2。NavigationLink目标不是惰性的
更新:从Xcode 11.4.1,iOS 13.4.1开始,Apple已修复此问题。NavigationLink目标视图现在延迟加载。出于历史目的,请随意阅读本节。
这意味着即使用户没有导航到目标视图,也将立即加载目标视图。要对此进行交叉检查,只需onAppear在目标视图的中添加一条打印语句。
目标视图不懒惰会影响具有视图列表的应用程序的性能。当列表中有数百行时,每行都有一个获取远程数据的目标视图,那么应用程序的性能肯定会受到影响。
值得庆幸的是,有一个解决方法,如推文中所示。通过在我们自己的自定义视图包裹的目的地来看,我们可以加载NavigationLink的destination懒洋洋的,如下图所示:
struct LazyView<Content: View>: View {
let build: () -> Content
init(_ build: @autoclosure @escaping () -> Content) {
self.build = build
}
var body: Content {
build()
}
}
最后,我们在上面的视图中封装了目的地:
NavigationLink(destination: LazyView(Text("Detail Screen"))){
Image("car")
.background(Color.red)
}.buttonStyle(PlainButtonStyle())
这无疑可以提高应用程序的性能。
结论
我们探索了NavigationLink在SwiftUI中设置a的不同方法,并解决了两个常见的陷阱。可以争辩说,NavigationLink默认情况下(在撰写本文时)目的地不是惰性的。
也许,从设计上讲,Apple不希望SwiftUI中的视图很笨重,因为重新加载视图应该是一种廉价的操作。
加入我们一起学习SwiftUI
QQ:3365059189
SwiftUI技术交流QQ群:518696470
教程网站:www.openswiftui.com