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

时间:2019-08-24 16:47:11

标签: ios swift animation uikit swiftui

在SwiftUI中,我们使用NavigationViewNavigationLink视图来执行导航(在segue中我们曾称UIKit为导航)。 UIKit中的标准segue是show segue。在SwiftUI中,我们可以简单地执行以下操作:

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

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

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

  • 我们可以决定根本不动画动画,实际上是在 故事板中,我们可以在 单击segue的属性检查器。这样,目标视图控制器将立即代替源视图控制器出现。
  • 或者我们可以决定执行自定义动画。通常,这是通过实现符合Animates协议的对象来完成的。所有的魔术都发生在UIViewControllerAnimatedTransitioning方法中,该方法使我们可以访问源视图控制器和目标视图控制器。

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

animateTransition

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

-(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];
    }];
}

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

1 个答案:

答案 0 :(得分:8)

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

寻找一种解决方法,我最终创建了一个名为swiftui-navigation-stackhttps://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")
            }
        }
    }
}

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

结果是:

enter image description here

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

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

对于交叉转换,我指定了:

let navigationTransition = AnyTransition.opacity.animation(.easeOut(duration: 2))

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

NavigationStackView(transitionType: .custom(navigationTransition))

enter image description here