如何为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
相关产品推荐
相关产品推荐

