SwiftUI 中的自定义转场动画(导航动画) [英] Custom segue animation (navigation animation) in SwiftUI

查看:26
本文介绍了SwiftUI 中的自定义转场动画(导航动画)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 SwiftUI 中,我们使用 NavigationViewNavigationLink 视图来执行导航(我们过去在 UIKitsegue>).UIKit 中的标准转场是 show 转场.在 SwiftUI 中,我们可以简单地做:

struct ContentView: 查看 {var主体:一些视图{导航视图{虚拟堆栈{NavigationLink(目的地:文本(目的地")){文本(导航!")}}}}}

具有完全相同的效果(即使 segue 这个词已经消失).

有时(实际上相当频繁)我们需要自定义转场动画.

  • 我们可以决定根本不为转场设置动画,事实上在我们可以在storyboard中找到属性Animates (true/false)通过单击 segue 来查看属性检查器.这样,目标视图控制器会立即出现在源视图控制器的位置.
  • 或者我们可以决定执行自定义动画.通常这是通过实现一个符合 UIViewControllerAnimatedTransitioning 协议的对象来完成的.所有的魔法都发生在 animateTransition 方法中,该方法使我们能够访问源视图控制器和目标视图控制器.

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

-(void)animateTransition:(id)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 动画:^{toVC.view.alpha = 1;fromVC.view.alpha = 0;}完成:^(BOOL完成){[fromVC.view removeFromSuperview];[transitionContext completeTransition:YES];}];}

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

struct ContentView: 查看 {var主体:一些视图{导航视图{虚拟堆栈{NavigationLink(目的地:文本(目的地")){文本(导航!")}}}.动画(无)}}

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

解决方案

遗憾的是,仍然无法在 SwiftUI (xCode 11.3.1) 中自定义 NavigationView 过渡动画.

为了找到一种方法,我最终创建了这个名为 swiftui-navigation-stack (

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

struct ContentView : 查看 {让 navigationTransition = AnyTransition.opacity.animation(.easeOut(duration: 2))var主体:一些视图{NavigationStackView(transitionType: .custom(navigationTransition)) {ZStack {Color.yellow.edgesIgnoringSafeArea(.all)PushView(目的地:View2()){文本(推")}}}}}结构视图2:查看{var主体:一些视图{ZStack {Color.green.edgesIgnoringSafeArea(.all)弹出视图{文本(POP")}}}}

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

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

持续 2 秒的淡入淡出过渡.然后我将这个转换传递给了 NavigationStackView:

NavigationStackView(transitionType: .custom(navigationTransition))

In SwiftUI we use NavigationView and NavigationLink views to perform navigations (what we used to call segue in UIKit). The standard segue in UIKit is the show segue. In SwiftUI we can simply do:

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

to have the exact same effect (even if the word segue has disappeared).

Sometimes (actually rather often) we need to customise the segue animation.

  • We can decide not to animate the segue at all, indeed in the storyboard we can find the attribute Animates (true/false) in the attribute inspector by clicking on a segue. This way the destination view controller appears immediately in place of the source view controller.
  • Or we can decide to perform a custom animation. Usually this is done by implementing an object that conforms to the UIViewControllerAnimatedTransitioning protocol. All the magic happens in the animateTransition method that gives us access to the source view controller and the destination view controller.

For example, a simple cross-fade segue animation could be something like:

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

Now the question: how can I get the same in SwiftUI? Is it possible not to animate a navigation or to customise the navigation animation? I expected to be able to do:

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

or something similar to prevent the animation (or to add a custom animation), but nothing changes.

解决方案

Unfortunately it's still not possible to customise the NavigationView transition animations in SwiftUI (xCode 11.3.1).

Looking for a way to do that I ended up creating this open source project called swiftui-navigation-stack (https://github.com/biobeats/swiftui-navigation-stack) that contains the NavigationStackView, a view that mimics the navigation behaviours of the standard NavigationView adding some useful features. For example you can turn off the transition animations or you can customise them with the transition you prefer.

Months ago I asked here above how to turn off transition animations. To do that you can use the NavigationStackView this way:

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

If you specify .none as transitionType you can turn off the animations. PushView and PopView are two views that allow you push and pop views (similar to the SwiftUI NavigationLink).

The result is:

If you, instead, want to customise the transition animation (as I asked in the question here above with the cross-fade example) you can do like this:

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

For a cross-fase transition I specified:

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

a cross fade transition that lasts 2 seconds. Then I passed this transition to the NavigationStackView:

NavigationStackView(transitionType: .custom(navigationTransition))

这篇关于SwiftUI 中的自定义转场动画(导航动画)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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