Swiftui:自定义NavigationView
- 1、第一步,创建自定义的NavigationView,命名为CustomNavView
struct CustomNavView<Content:View>: View {
// MARK: 内容
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
NavigationView {
///自定义的内容容器
CustomNavBarContainerView {
content
}
//隐藏系统navigationBar,使用自定义的navigationBar
.navigationBarHidden(true)
}
.navigationViewStyle(.stack)
}
}
// 设置右滑动可以退出页面
extension UINavigationController {
open override func viewDidLoad() {
super.viewDidLoad()
interactivePopGestureRecognizer?.delegate = nil
}
}
- 2、第二步,隐藏系统的navigationBar,创建NavigationView自定义内容容器
// MARK: 自定义内容容器
struct CustomNavBarContainerView<Content: View>: View {
let content: Content
@State private var showBackButton: Bool = true
@State private var title: String = ""
@State private var subtitle: String? = nil
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
VStack (spacing: 0) {
//自定义navigationBar
CustomNavBarView(showBackButton: showBackButton, title: title, subtitle: subtitle)
content
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
//动态变化标题
.onPreferenceChange(CustomNavBarTitilePreferenceKey.self) { value in
self.title = value
}
//动态变化副标题
.onPreferenceChange(CustomNavBarSubtitlePreferenceKey.self) { value in
self.subtitle = value
}
//是否展示返回键
.onPreferenceChange(CustomNavBarBackButtonHiddenPreferenceKey.self) { value in
self.showBackButton = !value
}
}
}
- 3、第三部,自定义创建navigationBar
//自定义navigationBar
struct CustomNavBarView: View {
//跳转返回
@Environment(\.presentationMode) var presentationMode
//返回控制
let showBackButton: Bool
//标题
let title: String
//副标题
let subtitle: String?
var body: some View {
HStack {
if showBackButton {
backButton
}
Spacer()
titleSection
Spacer()
if showBackButton {
backButton
.opacity(0)
}
}
.padding()
.accentColor(.white)
.foregroundColor(.white)
.font(.headline)
.background(Color.blue.ignoresSafeArea(edges: .top))
}
}
extension CustomNavBarView {
private var backButton: some View {
Button {
presentationMode.wrappedValue.dismiss()
} label: {
Image(systemName: "chevron.left")
}
}
private var titleSection: some View {
VStack (spacing: 4) {
Text(title)
.font(.title)
.fontWeight(.semibold)
if let subtitle = subtitle {
Text(subtitle)
}
}
}
}
- 4、第四步,通过preferenceKey通用设置标题和隐藏返回键
//自定义标题PreferenceKey
struct CustomNavBarTitilePreferenceKey: PreferenceKey {
static var defaultValue: String = ""
static func reduce(value: inout String, nextValue: () -> String) {
value = nextValue()
}
}
//自定义副标题PreferenceKey
struct CustomNavBarSubtitlePreferenceKey: PreferenceKey {
static var defaultValue: String? = nil
static func reduce(value: inout String?, nextValue: () -> String?) {
value = nextValue()
}
}
//自定义返回PreferenceKey
struct CustomNavBarBackButtonHiddenPreferenceKey: PreferenceKey {
static var defaultValue: Bool = false
static func reduce(value: inout Bool, nextValue: () -> Bool) {
value = nextValue()
}
}
extension View {
//设置标题
func customNavigationTitle(_ title: String) -> some View {
self
.preference(key: CustomNavBarTitilePreferenceKey.self, value: title)
}
//设置副标题
func customNavigationSubtitle(_ subtitle: String?) -> some View {
self
.preference(key: CustomNavBarSubtitlePreferenceKey.self, value: subtitle)
}
//是否隐藏返回键
func customNavigationBarBackButtonHidden(_ hidden: Bool) -> some View {
self
.preference(key: CustomNavBarBackButtonHiddenPreferenceKey.self, value: hidden)
}
//综合方法
func customNavBarItems(title: String = "", subtitle: String? = nil, backButtonHidden: Bool = false) -> some View {
self
.customNavigationTitle(title)
.customNavigationSubtitle(subtitle)
.customNavigationBarBackButtonHidden(backButtonHidden)
}
}
- 5、第五步,自定义创建NavigationLink跳转,命名为CustomNavLink
struct CustomNavLink<Label:View, Destination:View>: View {
let destination: Destination
let label: Label
init(destination: Destination, @ViewBuilder label: () -> Label) {
self.destination = destination
self.label = label()
}
var body: some View {
NavigationLink(
destination:
CustomNavBarContainerView(content: {
destination
}).navigationBarHidden(true)){
label
}
}
}
- 6、使用例子
struct AppNavBarView: View {
var body: some View {
CustomNavView {
ZStack {
Color.orange.ignoresSafeArea()
CustomNavLink(destination:
Text("Destination")
.customNavigationTitle("Second Screen")
.customNavigationSubtitle("Sibtitle should be showing!!")
) {
Text("Navigate")
}
} //: ZSTACK
.customNavBarItems(title: "New Title!", subtitle: nil, backButtonHidden: true)
}
}
}
-
7、效果图
navigationBar.gif 8、github代码地址:https://github.com/dennie-lee/SwiftUICustomNavBar