iOS 实现类似UIAlertView 和UIAlertController弹窗动画效果

UIAlertView和UIAlertController 项目中使用的很频繁的,但是系统的样式很多时候满足不了我们的需求,这时候我们需要自定义AlertView,但是我们又想做到像系统那样的动画效果该怎么来实现呢?其实比较难的就是AlertView出现的动画效果,所以我们这边把代码贴一下:

- (void)animationAlert:(UIView *)view
{
    CAKeyframeAnimation *popAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    popAnimation.duration = 0.4;
    popAnimation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.01f, 0.01f, 1.0f)],
                            [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1f, 1.1f, 1.0f)],
                            [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.9f, 0.9f, 1.0f)],
                            [NSValue valueWithCATransform3D:CATransform3DIdentity]];
    popAnimation.keyTimes = @[@0.0f, @0.5f, @0.75f, @1.0f];
    popAnimation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
                                     [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
                                     [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    [view.layer addAnimation:popAnimation forKey:nil];

}

这个就是类似UIAlertView弹出的动画效果,只要传入要显示动画的View即可。

至于上面的动画参数是怎么来,我这边简单的说明下,我们可以通过Runtime黑魔法去获取到系统AlertView的动画效果相关的参数,有兴趣的同学可以自己去实现下。

Objc Runtime
Objc Runtime是由一组处理Objctive-C动态语言运行时的API函数组成,这些函数都是一些比较底层的C函数。它有很多实用功能比如查看对象的成员,类/对象方法签名等等。这次我们要用的就是其中把对象方法调用替换的API。

void method_exchangeImplementations(Method m1, Method m2) 

这个函数的功能就是把类/对象的方法m1和m2进行调换。如果执行了这个函数,那么在App运行过程中所有调用方法m1的指令,最终都会执行成了方法m2。

方法调换
有了Objc Rumtime的API,就可以很方便的将调用系统库中方法的代码,执行成我们自己的代码了。所以我们想要知道Layer中加入了什么方法,只要把addAnimation:forKey:这个方法调换成我们自己的方法就行了。

所以要想知道这些动画的组成,我们就要从比较低层次的API:CALayer的一些调用开始。iOS动画最终都是加到Layer中的,加入Layer就要调用Layer对象这个方法:

- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key;

所以我们可以给CALayer加个Category代码如下

@implementation CALayer(Test)

+ (void)load{
    method_exchangeImplementations(class_getInstanceMethod([CALayer class], @selector(addAnimation:forKey:)), class_getInstanceMethod([CALayer class], @selector(hackedAddAnimation:forKey:)));
}

- (void)hackedAddAnimation:(CABasicAnimation *)anim forKey:(NSString *)key{
    [self hackedAddAnimation:anim forKey:key];
    if ([anim isKindOfClass:[CABasicAnimation class]]) {
        if ([anim.keyPath isEqualToString:@"transform"]) {
            if (anim.fromValue) {
                CATransform3D fromValue = [anim.fromValue CATransform3DValue];
                NSLog(@"From:%@",NSStringFromCGAffineTransform(CATransform3DGetAffineTransform(fromValue)));
            }
            if (anim.toValue) {
                CATransform3D toValue = [anim.toValue CATransform3DValue];
                NSLog(@"To:%@",NSStringFromCGAffineTransform(CATransform3DGetAffineTransform(toValue)));
            }
            if (anim.byValue) {
                CATransform3D byValue = [anim.byValue CATransform3DValue];
                NSLog(@"By:%@",NSStringFromCGAffineTransform(CATransform3DGetAffineTransform(byValue)));
            }
            NSLog(@"Duration:%.2f",anim.duration);
            NSLog(@"TimingFunction:%@",anim.timingFunction);
        }
    }
}

@end

最后在项目中随便写一个UIAlertView 并显示,然后看看控制台输入,我们就可以看到相关信息了

2017-06-01 19:13:11.795 Test[10952:c07] From:[0.01, 0, 0, 0.01, 0, 0]
2017-06-01 19:13:11.796 Test[10952:c07] Duration:0.20
2017-06-01 19:13:11.796 Test[10952:c07] TimingFunction:easeInEaseOut
2017-06-01 19:13:11.999 Test[10952:c07] From:[1.1, 0, 0, 1.1, 0, 0]
2017-06-01 19:13:12.000 Test[10952:c07] Duration:0.10
2017-06-01 19:13:12.000 Test[10952:c07] TimingFunction:easeInEaseOut
2017-06-01 19:13:12.101 Test[10952:c07] From:[0.9, 0, 0, 0.9, 0, 0]
2017-06-01 19:13:12.101 Test[10952:c07] Duration:0.10
2017-06-01 19:13:12.101 Test[10952:c07] TimingFunction:easeInEaseOut

你可能感兴趣的:(ios,动画,alertview,runtime)