iOS

iOS之动画集合(持续更新中...)

2018-10-19  本文已影响153人  Tomous

---------- CATransition(转场动画) ----------

先看几种效果图(差不多有10种效果,为便于阅读,我都放在了一个gif里面,大概1分钟左右,中间以停顿时间为间隔)


animation.gif

在控制器里创建一个ImageView接收图片

{
    UIImageView *_imageView;
    int _index;//图片索引
}
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    
    _index = 1;
    
    _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 300, 450)];
    _imageView.image = [UIImage imageNamed:@"1.jpg"];
    _imageView.center = self.view.center;
    _imageView.backgroundColor = [UIColor redColor];
    [self.view addSubview:_imageView];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    _index ++;
    if (_index == 4) {
        _index = 1;
    }
    [_imageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg", _index]]];
    
    CATransition *animation = [CATransition animation];
    /*
     Fade 逐渐消失;
     Reveal 旧的视图移走显示出新的视图;
     Push 旧的视图移走,新的视图移进来;
     MoveIn 新的视图把旧的视图掩盖
     */
//    animation.type = kCATransitionFade;
    
    /*这类是API引入的,在苹果官网是不会承认的,所以不建议使用
     1.animation.type = @"cube"; //立方体效果
     
     *2.animation.type = @"suckEffect";//犹如一块布被抽走
     
     *3. animation.type = @"oglFlip"; //上下翻转效果
     
     *4. animation.type = @"rippleEffect"; //滴水效果
     
     *5. animation.type = @"pageCurl"; //向左翻页
     
     *6.animation.type = @"pageUnCurl"; //向下翻页
     
     */
    animation.type = @"cube";//动画过渡类型
    
    //从哪个方向开始,top bottom left right
    animation.subtype = kCATransitionFromLeft;//动画过渡方向
    
    //动画时间间隔
    animation.duration = 1.5;
    
    //动画的切换时间速度
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];

 //   动画起点(在整体动画的百分比)
//    animation.startProgress = 0.5;

//   动画终点(在整体动画的百分比)
//    animation.endProgress = 0.5;
    
    //视图上加载动画(通过后面的forKey属性,在别的地方可以拿到这个动画的Key值)
    [_imageView.layer addAnimation:animation forKey:nil];
}
CAMediaTiming协议定义了在一段动画内用来控制逝去时间的属性的集合,CALayerCAAnimation都实现了这个协议。
durationrepeatCount代表持续和重复,默认都是0,但这不意味着动画时长为0秒,或者0次,这里的0仅仅代表了“默认”,也就是0.25秒和1次。
创建重复动画的另一种方式是使用repeatDuration属性,它让动画重复一个指定的时间,而不是指定次数。还可以设置一个叫做autoreverses的属性(BOOL类型),可以在动画结束后执行逆动画。

🌰项目拓展切换控制器的时候,给NavigationController设置个转场动画,效果图

11.gif
代码实现如下
    CATransition *animation = [CATransition animation];
    animation.type = @"cube";
    animation.duration = 0.5;
    animation.subtype = kCATransitionFromTop;
    [self.navigationController.view.layer addAnimation:animation forKey:nil];
    CATransitionViewController *VC = [[CATransitionViewController alloc]init];
    [self.navigationController pushViewController:VC animated:YES];

---------- CABasicAnimation ----------

🌰实现简单的一个动画

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"];
    //动画时间
    animation.duration = 0.8;
   //动画起始值和终止值的设置
    animation.fromValue = @(0.8);
    animation.toValue = @(0.8);
    //一个时间函数,表示它以怎么样的时间运行
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    animation.repeatCount = HUGE_VALF;
    animation.repeatDuration = 2;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    //添加动画
    [self.btn.layer addAnimation:animation forKey:@"后面可以通过这个key值拿到这个动画的标识"];

相关属性
keyPath :要改变的属性名称(传字符串)
fromValue:keyPath相应属性的初始值
toValue:keyPath相应属性的结束值
timingFunction:动画随时间运行的关系

一些常见的animationWithKeyPath值总结
说明 使用形式
transform.scale 比例转化 @(0.8)
transform.scale.x 宽的比例 @(0.8)
transform.scale.y 高的比例 @(0.8)
transform.rotation.x 围绕x轴旋转 @(M_PI)
transform.rotation.y 围绕y轴旋转 @(M_PI)
transform.rotation.z 围绕z轴旋转 @(M_PI)
cornerRadius 圆角的设置 @(50)
backgroundColor 背景颜色的变化 (id)[UIColor redColor].CGColor
bounds 大小,中心不变 [NSValue valueWithCGRect:CGRectMake:(0,0,200,200)]
position 位置(中心点的改变) [NSValue valueWithCGPoint:CGPointMake:(300,300)]
contents 内容(UIImageView的图片) imageAnimation.toValue = (id)[UIImage imageNamed:@"1"].CGImage
opacity 透明度 @(0.7)
contentsRect.size.width 横向拉伸缩放 @(0.4)//0~1之间的数字

----- CAKeyframeAnimation(关键帧动画) -----

🌰实现简单的一个动画


CAFrameAnimation.gif
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
    NSArray *rotationArr = @[@(M_PI_4),@(-M_PI_4),@(M_PI_4)];
    animation.values = rotationArr;
    animation.rotationMode = kCAAnimationRotateAuto;  //方向
    animation.duration = 3.0f;
    animation.keyTimes = @[@0.2 ,@0.8 ,@1.0];
    //animation.path = bezierPath.CGPath;
    animation.repeatCount = HUGE_VALF;
    [self.imageView.layer addAnimation:animation forKey:@"后面可以通过这个key值拿到这个动画的标识"];

属性说明
values:上述的NSArray对象。里面的元素称为“关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
path:可以设置一个CGPathRef、CGMutablePathRef,让图层按照路径轨迹移动。path只对CALayer的anchorPoint和position起作用。如果设置了path,那么values将被忽略
keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧。如果没有设置keyTimes,各个关键帧的时间是平分的
bezierPath:贝赛尔曲线路径,为动画提供一个动画移动的路线。

---------- UIBezierPath (贝赛尔曲线) ----------

简单的画一个曲线:

image.png
    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
    [bezierPath moveToPoint:CGPointMake(0, 450)];
    [bezierPath addCurveToPoint:CGPointMake(self.view.width, 450) controlPoint1:CGPointMake(self.view.width/2, 450-200) controlPoint2:CGPointMake(self.view.width/2, 450+200)];//一个曲线
    //路径样式
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = bezierPath.CGPath;
    shapeLayer.fillColor = [UIColor clearColor].CGColor; //填充色<默认黑色>
    shapeLayer.strokeColor = [UIColor blueColor].CGColor; //线色
    shapeLayer.lineWidth = 2;
    [self.view.layer addSublayer:shapeLayer];

UIBezierPath: 创建一个路径,画出一条曲线
CAShapeLayer: 对上面的线进行属性上的设置。最后添加到一个layer上。
UIBezierPath具体详解

---------- CAAnimationGroup(动画组) ----------

CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[animation,basicAnimation];
animationGroup.duration = 4;
animation.repeatCount = 9;
[_imageLayer addAnimation:animationGroup forKey:nill];

属性说明
animations:用来保存一组动画对象的NSArray
默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间

---------- POP(Spring弹簧效果)----------

1、简单使用-效果图


Spring1.gif

实现代码
先Pod

pod 'pop','~>1.0.10'

引入头文件

#import "POPSpringAnimation.h"
#import "POPBasicAnimation.h"

设置参数

static CGFloat const DCAnimationDelay = 0.1;//速度
static CGFloat const DCSpringFactor = 7;//幅度

使用

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.size = CGSizeMake(100, 80);
    btn.center = CGPointMake(self.view.centerX, self.view.centerY);
    btn.backgroundColor = [UIColor redColor];
    [btn addTarget:self action:@selector(btnDidClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
}
-(void)btnDidClick:(UIButton *)btn
{
    POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
    // 移动距离
    animation.fromValue = [NSValue valueWithCGRect:CGRectMake(btn.x, 0, btn.width, btn.height)];//开始位置
    animation.toValue = [NSValue valueWithCGRect:CGRectMake(btn.x, 200, btn.width, btn.height)];//结束位置
    
    // 从当前 + 1s后开始
    animation.beginTime = CACurrentMediaTime() + 1.0f;
    
    // 弹力--晃动的幅度 (springSpeed速度)
    animation.springBounciness = DCSpringFactor;
    animation.springSpeed = DCAnimationDelay;
    [btn pop_addAnimation:animation forKey:nil];
    
}

2、效果图


Spring2.gif

代码实现

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.size = CGSizeMake(100, 80);
    btn.center = CGPointMake(self.view.centerX, self.view.centerY);
    btn.backgroundColor = [UIColor redColor];
    [btn addTarget:self action:@selector(btnDidClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    
    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(btn.x, CGRectGetMaxY(btn.frame)-200, 100, 60)];
    label.backgroundColor = [UIColor lightGrayColor];
    label.textColor = [UIColor redColor];
    label.textAlignment = NSTextAlignmentCenter;
    label.text = @"0.0";
    self.label = label;
    [self.view addSubview:label];
    
}
-(void)btnDidClick:(UIButton *)btn
{
    // 初始化
    POPBasicAnimation *anim = [POPBasicAnimation animation];
    // 限时 1s. 2s.
    anim.duration = 3.0;
    POPAnimatableProperty * prop = [POPAnimatableProperty propertyWithName:@"count++" initializer:^(POPMutableAnimatableProperty *prop) {
        prop.readBlock = ^(id obj, CGFloat values[]){ values[0] = [[obj description] floatValue]; };
        prop.writeBlock = ^(id obj, const CGFloat values[])
        {
            [obj setText:[NSString stringWithFormat:@"%.2f",values[0]]];
        };
        prop.threshold = 0.01;
    }];
    
    anim.property = prop;
    anim.fromValue = @(0.0);
    anim.toValue = @(1314.52);
    [self.label pop_addAnimation:anim forKey:@"counting"];
}

3、效果图


Spring3.gif

代码实现

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    
    CALayer *layer1 = [CALayer layer];
    layer1.opacity = 1.0;
    layer1.transform = CATransform3DIdentity;
    layer1.masksToBounds = YES;
    layer1.backgroundColor = [UIColor redColor].CGColor;
    layer1.bounds = CGRectMake(0, 0, 100, 100);
    layer1.position = CGPointMake(self.view.centerX, self.view.centerY);
    layer1.cornerRadius = 50;
    [self.view.layer addSublayer:layer1];
    
    [self performAnimation:layer1];
    
}
- (void)performAnimation:(CALayer *)layer
{
    [layer pop_removeAllAnimations];
    POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
//    anim.duration = 1.0;
    static BOOL ani = YES;
    if (ani) {
        anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
    }else{
        anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.5, 1.5)];
    }
    ani = !ani;
    anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
        if (finished) {
            [self performAnimation:layer];
        }
    };
    [layer pop_addAnimation:anim forKey:@"Animation"];
}

项目拓展效果图

Spring.gif
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.size = CGSizeMake(100, 80);
    btn.center = CGPointMake(self.view.centerX, self.view.centerY);
    btn.backgroundColor = [UIColor redColor];
    [btn addTarget:self action:@selector(btnDidClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
}
-(void)btnDidClick
{
    [self setUpBackGroundView];
}
-(void)setUpBackGroundView{
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    UIView *backgroundView = [[UIView alloc]initWithFrame:self.view.bounds];
    backgroundView.userInteractionEnabled = YES;
    self.backgroundView = backgroundView;
    [window addSubview:backgroundView];
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapDidClick)];
    [backgroundView addGestureRecognizer:tap];
    
    UIImageView *backgroundImage = [[UIImageView alloc]initWithFrame:backgroundView.bounds];
    backgroundImage.image = [UIImage imageNamed:@"active_bj"];
    backgroundImage.userInteractionEnabled = YES;
    [backgroundView addSubview:backgroundImage];
    
    UIButton *cancleBtn = [[UIButton alloc]initWithFrame:CGRectMake((backgroundImage.width - 44) * 0.5, backgroundImage.height - 44 *2, 44, 44)];
    [cancleBtn setImage:[UIImage imageNamed:@"built_click"] forState:UIControlStateNormal];
    [cancleBtn addTarget:self action:@selector(cancleBtnDidClick) forControlEvents:UIControlEventTouchUpInside];
    [backgroundView addSubview:cancleBtn];
    
    NSArray *titles = @[@"你",@"就",@"说",@"我",@"帅",@"不",@"帅"];
    int maxCols = 3;
    CGFloat buttonW = self.backgroundView.width/3;
    CGFloat buttonH = 95;
    CGFloat buttonStartY = (self.backgroundView.height - 2 * buttonH) * 0.5;
    CGFloat buttonStartX = 20;
    CGFloat xMargin = (self.backgroundView.width - 2 * buttonStartX - maxCols * buttonW) / (maxCols - 1);
    for (int i = 0; i<titles.count; i++) {
        UIButton *button = [[UIButton alloc] init];
        button.tag = i;
        [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.backgroundView addSubview:button];
        
        // 设置内容
        button.titleLabel.font = [UIFont systemFontOfSize:50];
        [button setTitle:titles[i] forState:UIControlStateNormal];
        [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [button setImage:[UIImage imageNamed:titles[i]] forState:UIControlStateNormal];
        
        // 计算X\Y
        int row = i / maxCols;
        int col = i % maxCols;
        CGFloat buttonX = buttonStartX + col * (xMargin + buttonW);
        CGFloat buttonEndY = buttonStartY + row * buttonH;
        CGFloat buttonBeginY = buttonEndY - self.backgroundView.height;
        
        // 按钮动画
        POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
        anim.fromValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonBeginY, buttonW, buttonH)];
        anim.toValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonEndY, buttonW, buttonH)];
        anim.springBounciness = DCSpringFactor;
        anim.springSpeed = DCSpringFactor;
        anim.beginTime = CACurrentMediaTime() + DCAnimationDelay * i;
        [button pop_addAnimation:anim forKey:nil];
    }
}
- (void)buttonClick:(UIButton *)button
{
    [self cancelWithCompletionBlock:^{
        
        if (button.tag == 0 || button.tag == 1 || button.tag == 2) {
            NSLog(@"0 1 2");
            
        }else if (button.tag == 3){
            NSLog(@"3");
            
        }else if (button.tag == 4){
            
            NSLog(@"4");
            
        }else if (button.tag == 5){
            
            NSLog(@"5");
        }else if (button.tag == 6){
            NSLog(@"6");
        }
        
        UIViewController *vv = [[UIViewController alloc]init];
        vv.view.backgroundColor = [UIColor lightGrayColor];
        [self.navigationController pushViewController:vv animated:YES];
        
    }];
}
/**
 * 先执行退出动画, 动画完毕后执行completionBlock
 */
- (void)cancelWithCompletionBlock:(void (^)(void))completionBlock
{
    // 让控制器的view不能被点击
    self.backgroundView.userInteractionEnabled = NO;
    
    int beginIndex = 2;
    
    for (int i = beginIndex; i<self.backgroundView.subviews.count; i++) {
        UIView *subview = self.backgroundView.subviews[i];
        
        // 基本动画
        POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
        CGFloat centerY = subview.centerY + [UIScreen mainScreen].bounds.size.height;
        // 动画的执行节奏(一开始很慢, 后面很快)
        //        anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
        anim.toValue = [NSValue valueWithCGPoint:CGPointMake(subview.centerX, centerY)];
        anim.beginTime = CACurrentMediaTime() + (i - beginIndex) * DCAnimationDelay;
        [subview pop_addAnimation:anim forKey:nil];
        
        // 监听最后一个动画
        if (i == self.backgroundView.subviews.count - 1) {
            [anim setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
                //                [self dismissViewControllerAnimated:NO completion:nil];
                self.backgroundView.hidden = YES;
                
                // 执行传进来的completionBlock参数
                !completionBlock ? : completionBlock();
            }];
        }
    }
}
-(void)tapDidClick
{
    [self cancelWithCompletionBlock:nil];
}

-(void)cancleBtnDidClick
{
    [self cancelWithCompletionBlock:nil];
}
上一篇 下一篇

猜你喜欢

热点阅读