SwiftUI中的自定义segue动画(导航动画)

sup*_*cio 9 animation uikit ios swift swiftui

在SwiftUI我们使用NavigationViewNavigationLink意见进行导航(我们习惯称之为segueUIKit)。UIKit中的标准segue是showsegue。在SwiftUI中,我们可以简单地执行以下操作:

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: Text("Destination")) {
                    Text("Navigate!")
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

具有完全相同的效果(即使单词segue消失了)。

有时(实际上是经常),我们需要自定义segue动画。

  • 我们可以决定完全不对动画进行动画处理,实际上,在情节提要中,我们可以Animates通过单击动画来在属性检查器中找到该属性(true / false)。这样,目标视图控制器将立即代替源视图控制器出现。
  • 或者我们可以决定执行自定义动画。通常,这是通过实现符合UIViewControllerAnimatedTransitioning协议的对象来完成的。所有的魔术都发生在animateTransition使我们能够访问源视图控制器和目标视图控制器的方法中。

例如,一个简单的淡入淡出segue动画可能类似于:

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
    UIView* containerView = [transitionContext containerView];
    UIViewController* fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController* toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    toVC.view.alpha = 0;
    [containerView addSubview:toVC.view];

    [UIView animateWithDuration:1 animations:^{
        toVC.view.alpha = 1;
        fromVC.view.alpha = 0;
    } completion:^(BOOL finished) {
        [fromVC.view removeFromSuperview];
        [transitionContext completeTransition:YES];
    }];
}
Run Code Online (Sandbox Code Playgroud)

现在的问题是:如何在SwiftUI中获得相同的结果?是否可以不对导航设置动画或自定义导航动画?我希望能够做到:

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: Text("Destination")) {
                    Text("Navigate!")
                }
            }
        }
        .animation(nil)
    }
}
Run Code Online (Sandbox Code Playgroud)

或类似的阻止动画(或添加自定义动画)的内容,但没有任何变化。

sup*_*cio 8

不幸的是,仍然无法NavigationView在 SwiftUI (xCode 11.3.1) 中自定义过渡动画。

寻找一种方法,我最终创建了这个名为swiftui-navigation-stack( https://github.com/biobeats/swiftui-navigation-stack ) 的开源项目,其中包含NavigationStackView,一个模仿标准导航行为的视图,NavigationView添加了一些有用的特征。例如,您可以关闭过渡动画,也可以使用您喜欢的过渡自定义它们。

几个月前,我在这里问过如何关闭过渡动画。为此,您可以使用NavigationStackView这种方式:

struct ContentView : View {
    var body: some View {
        NavigationStackView(transitionType: .none) {
            ZStack {
                Color.yellow.edgesIgnoringSafeArea(.all)

                PushView(destination: View2()) {
                    Text("PUSH")
                }
            }
        }
    }
}

struct View2: View {
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            PopView {
                Text("POP")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您指定.nonetransitionType您可以关闭动画。PushViewPopView是两个允许您推送和弹出视图的视图(类似于 SwiftUI NavigationLink)。

结果是:

在此处输入图片说明

相反,如果您想要自定义过渡动画(正如我在上面使用交叉淡入淡出示例的问题中所问的那样),您可以这样做:

struct ContentView : View {
    let navigationTransition = AnyTransition.opacity.animation(.easeOut(duration: 2))

    var body: some View {
        NavigationStackView(transitionType: .custom(navigationTransition)) {
            ZStack {
                Color.yellow.edgesIgnoringSafeArea(.all)

                PushView(destination: View2()) {
                    Text("PUSH")
                }
            }
        }
    }
}

struct View2: View {
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)

            PopView {
                Text("POP")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于我指定的跨阶段过渡:

let navigationTransition = AnyTransition.opacity.animation(.easeOut(duration: 2))
Run Code Online (Sandbox Code Playgroud)

持续 2 秒的淡入淡出过渡。然后我将此转换传递给NavigationStackView

NavigationStackView(transitionType: .custom(navigationTransition))
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明