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

来源:互联网 发布:pcl icp源码 编辑:程序博客网 时间:2024/06/07 01:29

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.202017-06-01 19:13:11.796 Test[10952:c07] TimingFunction:easeInEaseOut2017-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.102017-06-01 19:13:12.000 Test[10952:c07] TimingFunction:easeInEaseOut2017-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.102017-06-01 19:13:12.101 Test[10952:c07] TimingFunction:easeInEaseOut