swift - 视图之间的转换
问题描述
我的应用程序中的视图之间的转换有一个小问题。这是我用来处理导航的代码:
class NavigationStack: ObservableObject {
fileprivate private(set) var navigationType: NavigationType = .push
fileprivate private(set) var navigationTransition: NavigationTransition = .scale
private var viewStack = ViewStack() {
didSet {
currentView = viewStack.peek()
}
}
@Published fileprivate var currentView: ViewElement?
func push<Element: View>(_ element: Element, withAnimation animation: NavigationTransition = .scale, withId identifier: String? = nil) {
navigationTransition = animation
withAnimation(navigationTransition.animation) {
navigationType = .push
viewStack.push(ViewElement(id: identifier == nil ? UUID().uuidString : identifier!,
wrappedElement: AnyView(element)))
}
}
func pop(to: PopDestination = .previous) {
withAnimation(navigationTransition.animation) {
navigationType = .pop
switch to {
case .root:
viewStack.popToRoot()
case .view(let viewId):
viewStack.popToView(withId: viewId)
default:
viewStack.popToPrevious()
}
}
}
private struct ViewStack {
private var views = [ViewElement]()
func peek() -> ViewElement? {
views.last
}
mutating func push(_ element: ViewElement) {
guard indexForView(withId: element.id) == nil else {
print("Duplicated view identifier: \"\(element.id)\". You are trying to push a view with an identifier that already exists on the navigation stack.")
return
}
views.append(element)
}
mutating func popToPrevious() {
_ = views.popLast()
}
mutating func popToView(withId identifier: String) {
guard let viewIndex = indexForView(withId: identifier) else {
print("Identifier \"\(identifier)\" not found. You are trying to pop to a view that doesn't exist.")
return
}
views.removeLast(views.count - (viewIndex + 1))
}
mutating func popToRoot() {
views.removeAll()
}
private func indexForView(withId identifier: String) -> Int? {
views.firstIndex {
$0.id == identifier
}
}
}
private struct ViewElement: Identifiable, Equatable {
let id: String
let wrappedElement: AnyView
static func == (lhs: ViewElement, rhs: ViewElement) -> Bool {
lhs.id == rhs.id
}
}
struct NavigationStackView<Root>: View where Root: View {
@ObservedObject private var navViewModel: NavigationStack = NavigationStack()
@ObservedObject private var popupViewModel: PopupManager = PopupManager()
private let rootViewID = "root"
private let rootView: Root
init(@ViewBuilder rootView: () -> Root) {
self.rootView = rootView()
}
var body: some View {
let showRoot = navViewModel.currentView == nil
let navigationType = navViewModel.navigationType
let transitions = navViewModel.navigationTransition.transitions
let showPopup = popupViewModel.openPopup
let popup = popupViewModel.popup
return ZStack {
Group {
if showRoot {
rootView
.id(rootViewID)
.transition(navigationType == .push ? transitions.push : transitions.pop)
.environmentObject(navViewModel)
.environmentObject(popupViewModel)
} else {
navViewModel.currentView!.wrappedElement
.id(navViewModel.currentView!.id)
.transition(navigationType == .push ? transitions.push : transitions.pop)
.environmentObject(navViewModel)
.environmentObject(popupViewModel)
}
}
if showPopup {
popup
.environmentObject(popupViewModel)
.ignoresSafeArea()
}
}
}
上面的代码按以下方式工作:我将 NavigationStack 包含到第一个屏幕,然后,当我想更改屏幕时,我使用 @EnvironmentObject NavigationStack 值及其方法 push。问题是当我想改变屏幕之间的过渡动画时(假设我想使用幻灯片而不是缩放),即将离开的屏幕仍然保持“旧”过渡(这是因为当 currentView 正在改变时,没有办法访问前一个视图并更改其转换)。消除此错误的唯一方法是在我要更改的视图中声明局部变量 @State transition: AnyTransition,并在调用方法 push 之前更改它:
@State private var transition: AnyTransition = .opacity
var body: some View {
ZStack {}
.transition(transition)
}
func openView() {
transition = .slide
navigationStack.push(newView(), withAnimation: .slide)
}
但我想实现对 NavigationStack(View) 类的更改。还有我的问题 - 有没有办法处理“旧”视图?我将非常感谢任何提示!
解决方案
推荐阅读
- dart - 如何在 Dart 中获取顶级函数的元数据
- mailgun - Linode 域管理器中的 MailGun TXT 记录
- php - Codeiniter Rest Server - 无法获取通过发布请求发送的数据
- mapreduce - 如何正确组织 RavenDB Map/Reduce 结果?
- java - 如何使用相对路径将文件写入目录
- python - 如何在 Python 中同步套接字消息
- python - 为什么我的 numpy 数组会随机转换为 int 类型?
- php - 给定数组中的随机值?
- javascript - 多个 Where 子句不适用于使用 java 脚本代码的 fire-store fire-base 查询
- android - 如何访问 onStop() 中的 Remove EventListener 而静态类中的 addValueEventListener