如何在 AnyView 制作的自定义 NavigationItem 之间向 Transitons 添加动画? [英] How do I add Animations to Transitons between custom NavigationItems made from AnyView?

查看:13
本文介绍了如何在 AnyView 制作的自定义 NavigationItem 之间向 Transitons 添加动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种方法可以向由 AnyView 制作的自定义 NavigationItem 之间的过渡添加动画,如 这篇文章?

Is there a way to add animations to transitions between custom NavigationItems 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.

我了解问题与使用 AnyViewsome View 进行类型擦除有关,如 这个答案Group 似乎是动画自定义视图的更好选择导航.

I understand the problem has to do with type-erasing some Views with AnyView, as described in this answer, and that Group seems to be a better choice for animating custom view navigations.

与使用 AnyView 和类型擦除相比,我更喜欢将条件逻辑封装在组视图中.那么你返回的类型是 Group,它会正确地制作动画.

Rather that using AnyView and type-erasure, I prefer to encapsulate the conditional logic inside of a Group view. Then the type you return is Group, which will animate properly.

我的想法已经用完了,我需要一些帮助.

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 添加动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆