NXNavigationExtensionSwiftUI 由 NXNavigationExtension 框架提供强力支持,他们的功能基本保持一致。注册完成之后需要在 NavigationView 中指定使用 .navigationViewStyle(.stack) 风格,但是目前仅支持 iOS 14 及以上系统的 StackNavigationViewStyle 风格,其他系统和 NavigationViewStyle 后续会不断完善。
下面是框架对 StackNavigationViewStyle 风格和 iOS 系统版本的支持情况:
| NavigationViewStyle / iOS version | iOS 13 | iOS 14 | iOS 15 |
|---|---|---|---|
| .automatic | ❌ | ❌ | ❌ |
| .stack | ❌ | ✅ | ✅ |
| .columns | ❌ | ❌ | ❌ |
-
💉 导入模块。
- 使用
CocoaPods集成:import NXNavigationExtension - 使用
Carthage管理:import NXNavigationExtensionSwiftUI
- 使用
-
💉 使用之前需要先在
AppDelegate中注册需要修改的导航控制器。
✅ 推荐
在 UIKit 版本中其实只需要 NXNavigationConfiguration().registerNavigationControllerClasses([YourNavigationController.self]) 这一行代码就完成导航控制器的注册了。但是在 SwiftUI 版本中还需要一个额外的步骤:指定 NXNavigationVirtualWrapperView 的查找规则,他是 SwiftUI 与 UIKit 之间的桥梁。查找规则开发者可以自定义,也可以使用框架提供的默认查找规则。
// AppDelegate.swift
var classes: [AnyClass] = []
if #available(iOS 15.0, *) {
classes = [
NSClassFromString("SwiftUI.SplitViewNavigationController"),
NSClassFromString("SwiftUI.UIKitNavigationController"),
].compactMap { $0 }
} else {
classes = [
NSClassFromString("SwiftUI.SplitViewNavigationController"), // iOS14
].compactMap { $0 }
}
let defaultConfiguration = NXNavigationConfiguration.default
defaultConfiguration.registerNavigationControllerClasses(classes) { navigationController, configuration in
// Configure
navigationController.nx_applyFilterNavigationVirtualWrapperViewRuleCallback(NXNavigationVirtualView.configureWithDefaultRule(for:))
return configuration
}// Example: ContentView.swift
import SwiftUI
import NXNavigationExtension
struct DestinationView: View {
@State private var context: NXNavigationRouter.Context = NXNavigationRouter.Context(routeName: "/destinationView")
var body: some View {
Button {
// NXNavigationRouter.of(context).pop()
NXNavigationRouter.of(context /* /destinationView */).popUntil("/contentView")
} label: {
Text("Pop")
.padding()
}
.useNXNavigationView(context: $context, onPrepareConfiguration: { configuration in
// `DestinationView` NavigationView backgroundColor
configuration.navigationBarAppearance.backgroundColor = .red
})
}
}
struct ContentView: View {
@State private var context: NXNavigationRouter.Context = NXNavigationRouter.Context(routeName: "/contentView")
var body: some View {
NavigationView {
NavigationLink { // 1. 使用 NavigationView 包装
DestinationView()
} label: {
Text("Push")
.padding()
.useNXNavigationView(context: $context /* /contentView */, onPrepareConfiguration: { configuration in
// 3. 修改导航栏背景颜色 ... `Text` NavigationView backgroundColor
configuration.navigationBarAppearance.backgroundColor = .brown
})
}
}
.navigationViewStyle(.stack) // 2. 使用 StackNavigationViewStyle 风格
}
}📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.tintColor = .red
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.useSystemBackButton = true
configuration.navigationBarAppearance.systemBackButtonTitle = title
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black]
})导航栏背景颜色默认使用系统蓝色 UIColor.systemBlue,这样处理能够快速辨别框架是否生效,也可以使用以下方式进行重写:
📝 示例代码
// 全局统一修改(不会覆盖基于视图控制器的修改)
let configuration = NXNavigationConfiguration.default
configuration.navigationBarAppearance.backgroundColor = .red
// 基于视图控制器修改(可以是基类视图控制器也是可以是特定需要修改的视图控制器)
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.backgroundColor = .red
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.backgroundImage = UIImage(named: "NavigationBarBackground88")
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.backgroundColor = .clear
configuration.navigationBarAppearance.shadowColor = .clear
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.backgroundColor = .clear
configuration.viewControllerPreferences.useBlurNavigationBar = true
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.backgroundColor = .systemBackground
configuration.navigationBarAppearance.shadowColor = .systemRed
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.backgroundColor = .systemBackground
configuration.navigationBarAppearance.shadowImage = UIImage(named: "NavigationBarShadowImage")
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.backImage = UIImage(systemName: "arrow.left")
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.backButtonCustomView = backButton
})📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.viewControllerPreferences.disableInteractivePopGesture = true
})📝 示例代码
- 全局有效
let configuration = NXNavigationConfiguration.default
configuration.navigationControllerPreferences.fullScreenInteractivePopGestureEnabled = true- 局部有效(在所处页面设置)
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.viewControllerPreferences.enableFullScreenInteractivePopGesture = true
})📝 示例代码
.callNXPopMethod: 调用nx_pop系列方法返回事件拦截。.backButtonAction: 点击返回按钮返回事件拦截。.backButtonMenuAction: 长按返回按钮选择菜单返回事件拦截。.popGestureRecognizer: 使用手势交互返回事件拦截。
Text("Destination")
.useNXNavigationView(onWillPopViewController: { interactiveType in
if selectedItemType == .backButtonAction && interactiveType == .backButtonAction ||
selectedItemType == .backButtonMenuAction && interactiveType == .backButtonMenuAction ||
selectedItemType == .popGestureRecognizer && interactiveType == .popGestureRecognizer ||
selectedItemType == .callNXPopMethod && interactiveType == .callNXPopMethod ||
selectedItemType == .all {
isPresented = true
return false
}
return true
})📝 示例代码
struct DestinationView: View {
@State private var context: NXNavigationRouter.Context
init() {
context = NXNavigationRouter.Context(routeName: "/currentRouteName")
}
var body: some View {
VStack {
Button {
NXNavigationRouter.of(context).pop()
} label: {
Text("Pop")
}
.useNXNavigationView(context: $context)
}
}
}- 需要注意的是
NXNavigationRouter.of(context)和NXNavigationRouter.of(context).nx用于调用系统pop和框架nx_pop系列方法 - 使用
NXNavigationRouter.of(context).nx方法弹出页面时会触发onWillPopViewController的回调。
📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.viewControllerPreferences.translucentNavigationBar = true
})📝 示例代码
Button {
NXNavigationRouter.of(context).setNeedsNavigationBarAppearanceUpdate()
} label: {
Text("Update")
}📝 示例代码
Text("Destination")
.useNXNavigationView(onPrepareConfiguration: { configuration in
configuration.navigationBarAppearance.useSystemBackButton = true
})