How do I add Animations to Transitons between custom NavigationItems made from AnyView?

拈花ヽ惹草 提交于 2019-12-19 05:00:14

问题


Is there a way to add animations to transitions between custom NavigationItems made from AnyView as described in this article?

I like everything about this NavigationStack system except for not being able to add any animated transitions.

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.

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.

I'll add my code for context.

SceneDelegate:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
...
    let contentView = ContentView().environmentObject(UserData())
...
}

ContentView:

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())
    }
}

NavigationHost:

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)
                    ...
                }
            }
    }
}

NavigationStack:

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
}


回答1:


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.

Note: transitions do not work in Preview (at least at my Xcode 11.2/iOS 13.2), so tested in Simulator or real device.

Here is how it looks:

Here is code:

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))
            }
        }

    }
}


来源:https://stackoverflow.com/questions/58908741/how-do-i-add-animations-to-transitons-between-custom-navigationitems-made-from-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!