Ben*_*n M 5 ios swift swiftui swiftui-navigationview
我正在开发一个需要自定义导航栏的项目,该导航栏将具有自定义按钮和标题样式,同时还允许主导航部分下方的附件视图。
本质上,我想抽象出根据演示风格选择自定义后退按钮的需要。如果它呈现在工作表中,我计划显示一个 X 图标。如果它被推到导航视图上,我想显示一个返回错误。如果它是根视图,我想完全隐藏该按钮。
我已经映射了presentationMode环境变量,但是当我访问该isPresented值时,我总是得到 true,即使在我的应用程序的根视图上也是如此。
以下是我正在从事的工作的总体思路:
import SwiftUI
struct CustomNavigationBar<Content>: View where Content: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
private let title: LocalizedStringKey
private let content: (() -> Content)?
private var backButton: AnyView? {
let button = Button(action: { self.presentationMode.wrappedValue.dismiss() }) {
// custom image extension, just resolves to a back icon
Image.Icons.arrowBack
}
if (presentationMode.wrappedValue.isPresented) {
return AnyView(button)
} else {
return nil
}
}
public init(_ title: LocalizedStringKey, content: (() -> Content)? = nil) {
self.title = title
self.content = content
}
var body: some View {
VStack {
content?()
Divider().foregroundColor(.gray)
}.navigationBarTitle(title, displayMode: .large)
.frame(minHeight: 96)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: backButton)
}
}
Run Code Online (Sandbox Code Playgroud)
有谁有使用 SwiftUI 访问视图在演示层次结构中的位置的经验或技巧吗?谢谢!
您可以使用SwiftUI-Introspect, 用于“从 SwiftUI 内省底层 UIKit 组件”。
这是您正在寻找的内容的工作示例。这是一个交互式示例,因此您可以单击不同的模式。
import Introspect
import SwiftUI
/* ... */
struct ContentView: View {
@State private var testing = 1
private let thingsToTest = 3
var body: some View {
VStack {
Picker("Testing", selection: $testing) {
ForEach(1 ... thingsToTest, id: \.self) { index in
Text("\(index)")
.tag(index)
}
}
.pickerStyle(SegmentedPickerStyle())
Divider()
Spacer()
switch testing {
case 1:
PresentationReader { kind in
Text("Hello! Kind: \(kind.rawValue)")
}
case 2:
NavigationView {
PresentationReader { kind in
Text("Hello! Kind: \(kind.rawValue)")
}
}
case 3:
Text("Parent")
.sheet(isPresented: .constant(true)) {
PresentationReader { kind in
Text("Hello! Kind: \(kind.rawValue)")
}
}
default:
fatalError("Unavailable")
}
Spacer()
}
}
}
Run Code Online (Sandbox Code Playgroud)
enum Kind: String {
case navigationView
case root
case sheet
}
struct PresentationReader<Content: View>: View {
typealias PresentedContent = (Kind) -> Content
@State private var kind: Kind = .root
private let content: PresentedContent
init(@ViewBuilder content: @escaping PresentedContent) {
self.content = content
}
var body: some View {
content(kind)
.presentationReader(kind: $kind)
}
}
extension View {
func presentationReader(kind: Binding<Kind>) -> some View {
self
.introspectViewController { vc in
let rootVC = UIApplication.shared.windows.first?.rootViewController
let isRoot = vc === rootVC
var isHosted: Bool { Introspect.findHostingView(from: vc.view) != nil }
if isRoot {
kind.wrappedValue = .root
} else if isHosted {
kind.wrappedValue = .navigationView
} else {
kind.wrappedValue = .sheet
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
它的工作原理是获取视图所在的当前视图控制器。
NavigationView或中.sheet(...))。NavigationView.NavigationView,则它位于 a 中.sheet(...)。经过这 3 项更改后,您的CustomNavigationBar外观将如下所示:
struct CustomNavigationBar<Content>: View where Content: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@State private var kind: Kind = .root // <--- CHANGE #1
private let title: LocalizedStringKey
private let content: (() -> Content)?
private var backButton: AnyView? {
let button = Button(action: { self.presentationMode.wrappedValue.dismiss() }) {
// custom image extension, just resolves to a back icon
Image.Icons.arrowBack
}
if kind == .navigationView { // <--- CHANGE #2
return AnyView(button)
} else {
return nil
}
}
public init(_ title: LocalizedStringKey, content: (() -> Content)? = nil) {
self.title = title
self.content = content
}
var body: some View {
VStack {
content?()
.presentationReader(kind: $kind) // <--- CHANGE #3
Divider().foregroundColor(.gray)
}.navigationBarTitle(title, displayMode: .large)
.frame(minHeight: 96)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: backButton)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5259 次 |
| 最近记录: |