Swiftui:自定义NavigationView

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)
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容