问题描述
有没有办法为由 AnyView
制作的自定义 NavigationItem
之间的过渡添加动画,如 这篇文章?
Is there a way to add animations to transitions between custom NavigationItem
s made from AnyView
as described in this article?
我喜欢这个 NavigationStack
系统的一切,除了不能添加任何动画过渡.
I like everything about this NavigationStack
system except for not being able to add any animated transitions.
我了解问题与使用 AnyView
对 some View
进行类型擦除有关,如 这个答案,Group
似乎是动画自定义视图的更好选择导航.
I understand the problem has to do with type-erasing some View
s with AnyView
, as described in this answer, and that Group
seems to be a better choice for animating custom view navigations.
与使用 AnyView 和类型擦除相比,我更喜欢将条件逻辑封装在组视图中.那么你返回的类型是 Group,它会正确地制作动画.
我的想法已经用完了,我需要一些帮助.
I've run out of ideas and I need some help.
我将添加上下文代码.
场景委托:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
...
let contentView = ContentView().environmentObject(UserData())
...
}
内容视图:
struct ContentView: View {
@EnvironmentObject var userData: UserData
var body: some View {
NavigationHost()
.environmentObject(NavigationStack(
NavigationItem(view: AnyView(
(userData.isSignedIn ? AnyView(HomeView()) : AnyView(RegisterView1(profile: Profile.default)) )
.transition(.move(edge: .trailing))
.animation(Animation.linear(duration: 1))))))
//this animation works for some reason, but only this one.
.environmentObject(UserData())
}
}
导航主机:
struct NavigationHost: View{
@EnvironmentObject var navigation: NavigationStack
@EnvironmentObject var userData: UserData
var body: some View {
ZStack {
self.navigation.currentView.view
.environmentObject(self.userData)
.environmentObject(self.navigation)
...
}
}
}
}
导航堆栈:
final class NavigationStack: ObservableObject {
@Published var viewStack: [NavigationItem] = []
@Published var currentView: NavigationItem
init(_ currentView: NavigationItem ){
print("Navigation Stack Initialized")
self.currentView = currentView
}
func back() {
if viewStack.count == 0 {
return
}
let last = viewStack.count - 1
currentView = viewStack[last]
viewStack.remove(at: last)
}
navigation.advance(NavigationItem(AnyView))
func advance(_ view: NavigationItem) {
viewStack.append( currentView )
currentView = view
}
func home() {
currentView = NavigationItem( view: AnyView(HomeView()) )
viewStack.removeAll()
}
}
struct NavigationItem{
var view: AnyView
}
推荐答案
此处更新了该文章中的实体,以在屏幕之间采用简单的动画过渡.所有这些都是沙哑的,仅用于演示,但希望它能以某种方式有所帮助.
Here is updated entities from that article to adopt simple animated transitions between screens. All that is scratchy and only for demo, but hope it could be helpful somehow.
注意:过渡在预览版中不起作用(至少在我的 Xcode 11.2/iOS 13.2 中),因此在模拟器或真实设备中进行了测试.
Note: transitions do not work in Preview (at least at my Xcode 11.2/iOS 13.2), so tested in Simulator or real device.
这是它的外观:
代码如下:
final class NavigationStack: ObservableObject {
enum Direction {
case root
case forward
case backward
}
@Published var viewStack: [NavigationItem] = []
@Published var currentView: NavigationItem
@Published var navigate: Direction = .root
init(_ currentView: NavigationItem ){
self.currentView = currentView
}
func unwind(){
if viewStack.count == 0{
return
}
let last = viewStack.count - 1
currentView = viewStack[last]
withAnimation {
self.navigate = .backward
}
viewStack.remove(at: last)
}
func advance(_ view:NavigationItem){
viewStack.append( currentView)
currentView = view
withAnimation {
self.navigate = .forward
}
}
func home( ){
currentView = NavigationItem(view: AnyView(HomeView()))
viewStack.removeAll()
withAnimation {
self.navigate = .root
}
}
}
struct NavigationHost: View{
@EnvironmentObject var navigation: NavigationStack
var body: some View {
ZStack(alignment: .topLeading) {
if navigation.navigate == .root {
self.navigation.currentView.view
}
else if navigation.navigate == .backward {
self.navigation.currentView.view
.transition(.move(edge: .leading))
}
if navigation.navigate == .forward {
self.navigation.currentView.view
.transition(.move(edge: .trailing))
}
}
}
}
这篇关于如何在从 AnyView 制作的自定义 NavigationItem 之间向 Transitons 添加动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!