iOS自定义转场动画

在iOS程序里出现得最多的转场动画,就是UINavigationController的Push和Pop了,看多了就觉得有些无聊了,还好苹果提供了自定义转场动画的API,往下看。

首页,要明白既然转场动画是通过导航控制器来完成(UIViewController模态除外),那么就往UINavigationController看,既然是转场,那么在两个控制器切换的中间,就是转场动画发生的地方,一提到“将要出现”,“已经出现”,“将要消失”,“已经消失”,条件反射就想到了UINavigationController的代理方法:

@protocol UINavigationControllerDelegate <NSObject>

@optional

// Called when the navigation controller shows a new top view controller via a push, pop or setting of the view controller stack.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

- (NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController NS_AVAILABLE_IOS(7_0);
- (UIInterfaceOrientation)navigationControllerPreferredInterfaceOrientationForPresentation:(UINavigationController *)navigationController NS_AVAILABLE_IOS(7_0);

- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);

- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                   animationControllerForOperation:(UINavigationControllerOperation)operation
                                                fromViewController:(UIViewController *)fromVC
                                                  toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);

@end

注意最后两个方法,就是它了,注意可用的iOS版本:NS_AVAILABLE_IOS(7_0)

- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);
这个方法是讲的手势百分比交互,今天不谈,说最后一个方法,它的返回值是

id <UIViewControllerAnimatedTransitioning>,一个遵循UIViewControllerAnimatedTransitioning的对象,点开它:

@protocol UIViewControllerAnimatedTransitioning <NSObject>

// This is used for percent driven interactive transitions, as well as for container controllers that have companion animations that might need to
// synchronize with the main animation. 
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext;
// This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;


@optional
两个方法,第一个是返回动画持续时间,第二个是动画具体内容。

说了这么多理论,总结一下自定义转场动画大致的设置思路:

1、自定义一个继承自NSObject并且遵从UIViewControllerAnimatedTransitioning协议的类,里面实现协议方法,设置好动画时长和具体内容;

2、在转场动画发生的viewcontroller里,遵从UINavigationControllerDelegate协议,实现协议方法

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
在该方法里返回自定义的动画类的一个对象即可。

示例:



新建一个有两个viewcontroller的工程:FirstViewController、SecondViewcontroller,将FirstViewcontroller加到一个导航控制器里,它的view上有一个“push”按钮,点它可以将SecondViewController push进来,SecondViewController上有一个“pop”按钮,点它可以pop到FirstViewController,描述得已经很清楚了吧。

创建两个继承自NSObject的类,一个叫PushAnimation,一个叫PopAnimation,它们都遵循UIViewControllerAnimatedTransitioning协议:

@interface PushAnimation : NSObject<UIViewControllerAnimatedTransitioning>

@end

@interface PopAnimation : NSObject<UIViewControllerAnimatedTransitioning>

@end

在PushAnimation.h
//返回动画持续时间
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return 2.0f;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    //获取起点controller
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    
    //获取终点controller
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    //获取转场容器视图
    UIView *containerView = [transitionContext containerView];
    
    //设置终点视图的frame
    CGRect frame = [transitionContext initialFrameForViewController:fromVC];
    CGRect offScreenFrame = frame;
    //先将其设置到屏幕外边,通过动画进入
    offScreenFrame.origin.x = offScreenFrame.size.width;
    toVC.view.frame = offScreenFrame;
    
    //添加视图
    [containerView addSubview:toVC.view];
    
    //执行动画
    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        //设置缩放和透明度
        fromVC.view.transform = CGAffineTransformMakeScale(0.8, 0.8);
        fromVC.view.alpha = 0.5;
        //设置位置
        toVC.view.frame = frame;
    } completion:^(BOOL finished) {
        fromVC.view.transform = CGAffineTransformIdentity;
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
}

在PopAnimation里实现下面方法(push的逆动画,其实可以只创建一个类,通过“顺”or“逆”来判断执行的动画):

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return 2.0f;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    UIView *containerView = [transitionContext containerView];
    
    toVC.view.transform = CGAffineTransformMakeScale(0.8, 0.8);
    toVC.view.alpha = 0.5;
    CGRect frame = [transitionContext initialFrameForViewController:fromVC];
    CGRect offScreenFrame = frame;
    offScreenFrame.origin.x = offScreenFrame.size.width;
    
    [containerView insertSubview:toVC.view belowSubview:fromVC.view];
    
    
    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        toVC.view.transform = CGAffineTransformIdentity;
        toVC.view.alpha = 1.0f;
        fromVC.view.frame = offScreenFrame;
    } completion:^(BOOL finished) {
        fromVC.view.transform = CGAffineTransformIdentity;
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
}

在FirstViewController.m里添加下面代码:

#import "PushAnimation.h"

@interface FirstViewController ()<UINavigationControllerDelegate>
{
    PushAnimation *_pushAni;
}
@end

- (void)viewDidLoad {
    [super viewDidLoad];
    _pushAni = [PushAnimation new];
}

- (void)viewDidAppear:(BOOL)animated
{
    self.navigationController.delegate = self;
    [super viewDidAppear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    if (self.navigationController.delegate == self) {
        self.navigationController.delegate = nil;
    }
    [super viewDidDisappear:animated];
}

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
    if (operation == UINavigationControllerOperationPush) {
        return _pushAni;
    }
    return nil;
}

同样,在SecondViewController里设置pop的动画代码,即可,更好的方法,可以写一个继承自UINavigationController的子类,统一实现协议方法。






### IntelliJ IDEA 中通义灵码 AI 功能介绍 IntelliJ IDEA 提供了一系列强大的工具来增强开发体验,其中包括与通义灵码 AI 相关的功能。这些功能可以帮助开发者更高效地编写代码并提高生产力。 #### 安装通义灵码插件 为了使用通义灵码的相关特性,在 IntelliJ IDEA 中需要先安装对应的插件: 1. 打开 **Settings/Preferences** 对话框 (Ctrl+Alt+S 或 Cmd+, on macOS)。 2. 导航到 `Plugins` 页面[^1]。 3. 在 Marketplace 中搜索 "通义灵码" 并点击安装按钮。 4. 完成安装后重启 IDE 使更改生效。 #### 配置通义灵码服务 成功安装插件之后,还需要配置通义灵码的服务连接信息以便正常使用其提供的各项能力: - 进入设置中的 `Tools | Qwen Coding Assistant` 菜单项[^2]。 - 填写 API Key 和其他必要的认证参数。 - 测试连接以确认配置无误。 #### 使用通义灵码辅助编程 一旦完成上述准备工作,就可以利用通义灵码来进行智能编码支持了。具体操作如下所示: ##### 自动补全代码片段 当输入部分语句时,IDE 将自动提示可能的后续逻辑,并允许一键插入完整的实现方案[^3]。 ```java // 输入 while 循环条件前半部分... while (!list.isEmpty()) { // 激活建议列表选择合适的循环体内容 } ``` ##### 解释现有代码含义 选中某段复杂的表达式或函数调用,右键菜单里会有选项可以请求通义灵码解析这段代码的作用以及优化意见。 ##### 生产测试案例 对于已有的业务逻辑模块,借助于通义灵码能够快速生成单元测试框架及初始断言集,减少手动构建的成本。 ```python def test_addition(): result = add(2, 3) assert result == 5, f"Expected 5 but got {result}" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值