You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Xamarin.iOS的Push类型Segue添加Slide to the right动画?

嘿,我来帮你搞定这个自定义Push Segue的右滑动画问题!另外先纠正个小误解:Push类型Segue不会舍弃之前的视图控制器,它是把新控制器加入导航栈,之前的控制器依然保存在栈里,之后可以通过Pop操作返回;Modal才是独立的模态层级,和导航栈无关。

要实现Push时的“Slide to the right”动画,我们需要自定义Segue来实现,具体步骤如下:

实现Push类型Segue的“Slide to the right”自定义动画

1. 创建自定义Segue类

新建一个继承自UIStoryboardSegue的类(比如命名为SlideRightPushSegue),重写perform()方法来实现动画逻辑:

Swift版本

import UIKit

class SlideRightPushSegue: UIStoryboardSegue {
    override func perform() {
        // 获取源控制器、目标控制器和导航控制器
        guard let sourceVC = source as? UIViewController,
              let destinationVC = destination as? UIViewController,
              let navigationController = sourceVC.navigationController else {
            super.perform()
            return
        }
        
        // 把目标视图初始位置放在屏幕右侧外
        let screenBounds = UIScreen.main.bounds
        destinationVC.view.frame = CGRect(x: screenBounds.width, y: 0, width: screenBounds.width, height: screenBounds.height)
        
        // 将目标视图临时添加到导航控制器的视图中
        navigationController.view.addSubview(destinationVC.view)
        
        // 执行滑入动画:源视图左移,目标视图从右侧滑入屏幕
        UIView.animate(withDuration: 0.3, animations: {
            sourceVC.view.frame = CGRect(x: -screenBounds.width, y: 0, width: screenBounds.width, height: screenBounds.height)
            destinationVC.view.frame = screenBounds
        }) { _ in
            // 动画结束后,正式将目标控制器推入导航栈,恢复源视图的位置
            sourceVC.view.frame = screenBounds
            navigationController.pushViewController(destinationVC, animated: false)
        }
    }
}

Objective-C版本

#import "SlideRightPushSegue.h"

@implementation SlideRightPushSegue

- (void)perform {
    UIViewController *sourceVC = self.sourceViewController;
    UIViewController *destinationVC = self.destinationViewController;
    UINavigationController *navigationController = sourceVC.navigationController;
    
    if (!navigationController) {
        [super perform];
        return;
    }
    
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    // 设置目标视图初始位置在屏幕右侧外
    destinationVC.view.frame = CGRectMake(screenBounds.size.width, 0, screenBounds.size.width, screenBounds.size.height);
    
    // 临时添加到导航控制器视图
    [navigationController.view addSubview:destinationVC.view];
    
    // 执行动画
    [UIView animateWithDuration:0.3 animations:^{
        sourceVC.view.frame = CGRectMake(-screenBounds.size.width, 0, screenBounds.size.width, screenBounds.size.height);
        destinationVC.view.frame = screenBounds;
    } completion:^(BOOL finished) {
        // 动画结束后正式推入导航栈
        sourceVC.view.frame = screenBounds;
        [navigationController pushViewController:destinationVC animated:NO];
    }];
}

@end

2. 在Storyboard中配置自定义Segue

  • 打开你的Storyboard,按住Ctrl键从源视图控制器拖动到目标视图控制器,选择Custom类型的Segue。
  • 在右侧属性检查器(Attributes Inspector)中,将Segue的Class设置为我们刚创建的SlideRightPushSegue。
  • 确认Segue的Kind选项是Push(默认Custom类型可能需要手动选择,别选成Modal了)。

3. 可选:添加对应的返回动画

如果需要从目标控制器返回时也有右滑的动画效果,可以给导航控制器设置自定义的转场动画。在目标控制器中添加以下代码:

Swift版本

import UIKit

extension YourDestinationViewController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        // 只有Pop操作时使用自定义动画
        if operation == .pop {
            return SlideRightPopAnimator()
        }
        return nil
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.delegate = self
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // 离开页面时取消代理,避免影响其他页面的转场
        navigationController?.delegate = nil
    }
}

// 自定义Pop动画类
class SlideRightPopAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.3 // 动画时长可自行调整
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let fromVC = transitionContext.viewController(forKey: .from),
              let toVC = transitionContext.viewController(forKey: .to) else {
            return
        }
        
        let containerView = transitionContext.containerView
        containerView.addSubview(toVC.view)
        
        let screenBounds = UIScreen.main.bounds
        // 初始位置:源视图在屏幕内,目标视图在屏幕左侧外
        toVC.view.frame = CGRect(x: -screenBounds.width, y: 0, width: screenBounds.width, height: screenBounds.height)
        
        // 执行返回动画:源视图右滑出去,目标视图从左侧滑入
        UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
            fromVC.view.frame = CGRect(x: screenBounds.width, y: 0, width: screenBounds.width, height: screenBounds.height)
            toVC.view.frame = screenBounds
        }) { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}

注意事项

  • 确保源视图控制器已经嵌入在UINavigationController中,Push Segue只能在导航栈中使用。
  • 动画时长可以根据需求调整,示例中用的0.3秒是比较流畅的速度,你可以改成自己喜欢的数值。

内容的提问来源于stack exchange,提问作者Gino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:32:36