SwiftUI控件NavigationStack进阶
在SwiftUI中,如果我们想要给app添加一个到导航栏,可以使用NavigationStack控件,需要注意的是NavigationStack是iOS 16之后增加的,旨在替代原来的NavigationView,所以如果你的app 运行在iOS 16之前的版本需要使用NavigationView。
在之前的文章中,我们已经接受了NavigationStack的基本使用,接下来我们将主要介绍NavigationStack自定义,即自定义导航栏样式。
初始项目代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23struct ContentView: View {
var books: [String] = ["三国演义","水浒传", "红楼梦", "西游记"]
var body: some View {
NavigationStack {
List(books, id: \.self) { book in
NavigationLink {
DetailContentView(book: book)
} label: {
Text(book)
.bold()
}
}
.navigationTitle("四大名著")
}
}
}
struct DetailContentView: View {
var book: String
var body: some View {
Text(book)
}
}
自定义导航栏字体和文字颜色
目前,SwiftUI中并没有提供可以定义导航栏样式的修饰器,这里我们需要使用UIKit提供的UINavigationBarAppearance API 来实现。
例如,如果我们想要自定义导航栏上的标题字体和颜色,可以使用下面的方式:1
2
3
4
5
6
7
8
9
10
11
12init() {
let navigationBarAppearance = UINavigationBarAppearance()
// 大标题字体样式
navigationBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.red, .font: UIFont(name: "Nunito-Regular", size: 30)!]
// 小标题字体样式
navigationBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.red, .font: UIFont(name: "Nunito-Regular", size: 20)!]
// 标准样式
UINavigationBar.appearance().standardAppearance = navigationBarAppearance
UINavigationBar.appearance().scrollEdgeAppearance = navigationBarAppearance
UINavigationBar.appearance().compactAppearance = navigationBarAppearance
}
这里我们是在ContetnView进行初始化的时候就来设置导航栏的标题,即1
2
3
4
5
6
7
8
9
10struct ContentView: View {
var body: some View {
}
// ContentView的初始化方法
init() {
}
}
自定义返回按钮的图片和颜色
如果我们只是想要改变默认的返回按钮的图片和颜色,那么我们只需修改UINavigationBarAppearance实例对象的属性即可,即1
navigationBarAppearance.setBackIndicatorImage(UIImage(systemName: "arrow.turn.up.left"), transitionMaskImage: UIImage(systemName: "arrow.turn.up.left"))
如果是改变返回按钮字体的颜色,只需要修改NavigationStack强调色或者说添加tint修饰器,即1
2
3
4NavigationStack {
}
.tint(.black)
但是,如果我们想要完全自定义个返回按钮,就需要先隐藏NavigationStack原来默认的按钮,使用SwiftUI 提供的navigationBarBackButtonHidden修饰器。
需要注意的是,这个修饰器需要添加到跳转后的子视图上面,在这个例子中就是我们的DetailContentView视图,即1
2DetailContentView(book: book)
.navigationBarBackButtonHidden(true)
此时,当我们再点击跳转过去的时候,下一个页面已经没有默认的返回按钮了。
接着,我们可以使用toolBar给DetailContentView自定义一个返回的按钮,具体实现的代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19struct DetailContentView: View {
var book: String
(\.dismiss) var dismiss // 通过dismiss 关键字获取dismiss方法,实现返回上一页
var body: some View {
Text(book)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button(action: {
dismiss()
}, label: {
Text("\(Image(systemName: "chevron.left")) \(book)")
.foregroundStyle(.blue)
})
}
}
// 导航栏调整为小标题样式
.navigationBarTitleDisplayMode(.inline)
}
}
在上面的代码中,我们使用toolBar修饰器和ToolBarItem控件去定义了一个位于左上角的返回按钮,然后使用Environment获取到了dismiss方法来帮助我们返回上一页。
需要注意的一点是,在iOS 15.0之前的系统中,想要实现返回上一页需要使用下面的这种方法:1
(\.presentationMode) var presentationMode
然后在按钮的action部分调用下面的代码:1
presentationMode.wrappedValue.dismiss()