【发布时间】:2022-07-21 01:34:09
【问题描述】:
来自 UIKit,我正在 SwiftUI 中构建自己的模态导航逻辑,因为我想要自定义布局和动画。在这里,我想要一个像这样的通用底页:
我已经通过以下代码实现了一些接近:
enum ModalType: Equatable {
case normal // ...
@ViewBuilder
var screen: some View {
switch self {
case .normal: ModalView()
// ...
}
}
}
struct ContentView: View {
@State var presentedModal: ModalType?
var body: some View {
VStack {
Button("Present modal", action: { presentedModal = .normal }).foregroundColor(.black)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.gray)
.modifier(ModalBottomViewModifier(item: $presentedModal) { $0.screen })
}
}
struct ModalView: View {
@Environment(\.dismissModal) private var dismissModal
var body: some View {
VStack {
Button("Close", action: { dismissModal() })
}
.frame(maxWidth: .infinity)
.frame(height: 300)
.background(
RoundedRectangle(cornerRadius: 32)
.fill(.black.opacity(0.5))
.edgesIgnoringSafeArea([.bottom])
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
// MARK: - Modal logic
struct ModalBottomViewModifier<Item:Equatable, V:View>: ViewModifier {
@Binding var item: Item?
@ViewBuilder var view: (Item) -> V
func body(content: Content) -> some View {
ZStack(alignment: .bottom) {
content
if let item = item {
view(item)
.environment(\.dismissModal, { self.item = nil })
.transition(.move(edge: .bottom))
}
}
.animation(.easeOut, value: item)
}
}
private struct ModalDismissKey: EnvironmentKey {
static let defaultValue: () -> Void = {}
}
extension EnvironmentValues {
var dismissModal: () -> Void {
get { self[ModalDismissKey.self] }
set { self[ModalDismissKey.self] = newValue }
}
}
现在我想让这个系统可重复使用,这样我就不必将ModalBottomViewModifier 添加到我所有的应用程序屏幕上。为此,我希望能够将修饰符应用于按钮而不是屏幕,就像 fullScreenCover 一样:
Button("Present modal", action: { isPresented = true }).foregroundColor(.black)
.fullScreenCover(isPresented: $isPresented) { ModalView() }
这在我当前的解决方案中是不可能的,因为模态视图将出现在按钮旁边,而不是全屏。
我怎样才能做到这一点?还是我应该做一些不同的事情?
【问题讨论】:
-
我相信你可以创建一个返回视图的函数。
-
可以通过在非常根级别应用模态修饰符并通过功能修饰符的首选项键将条件控制转移到那里来实现(就像 fullScreenCover 一样)。
标签: swiftui