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、效果图
    请添加图片描述

  • 8、github代码地址:https://github.com/dennie-lee/SwiftUICustomNavBar

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值