1. 程式人生 > >ios動畫學習(三)

ios動畫學習(三)

使用Core Animation宣告動畫

CoreAnimation框架最基本的抽象類是CAAnimation類,這個類按照CAMediaTiming協議,提供了動畫執行時間、速度,及重複次數這些基本設定,同時,它也遵循了CAAction協議,可提供該動畫被圖層驅動時的響應。 CAAnimation類之下定義了一系列的類,用來定義更具體的漸變動畫類。層級如下:
下面是CABasicAnimation類使用:
- (IBAction)down:(id)sender {
    //使用CABasicAnimation建立動畫,fromValue、toValue、byValue數值以oc物件形式存在
    CABasicAnimation * moveDown = [CABasicAnimation animationWithKeyPath:@"position.y"];
    //是檢視在動畫執行完成後,停留在最後位置
    //moveDown.removedOnCompletion = NO;
    //moveDown.fillMode = kCAFillModeForwards;
    
    //動畫執行完成後,自動以動畫形式原路返回
    //moveDown.autoreverses = YES;
    
    //動畫重複執行的次數
    //moveDown.repeatCount = 2;
    moveDown.duration = 2.0;
    moveDown.toValue = [NSNumber numberWithInt:layer.position.y+100];
    //把動畫應用到圖層上,並且給動畫加一個識別符號moveDown
    [layer addAnimation:moveDown forKey:@"moveDown"];
}

- (IBAction)up:(id)sender {
    //使用CABasicAnimation建立動畫
    //這種宣告動畫的方式改變的只有介面本身,而非物件屬性。這和設定物件屬性製作成的動畫有非常大的區別。
    CABasicAnimation * moveUp = [CABasicAnimation animationWithKeyPath:@"position.y"];
    moveUp.duration = 5.0;
    //把正數封裝成物件型別
    moveUp.toValue = [NSNumber numberWithInt:layer.position.y-100];
    //把動畫應用到圖層上,並且給動畫加一個識別符號moveUp
    [layer addAnimation:moveUp forKey:@"moveUp"];
}

- (IBAction)stopdown:(id)sender {
    //通過動畫識別符號取消動畫
    [layer removeAnimationForKey:@"moveDown"];
}

- (IBAction)stopup:(id)sender {
    //通過動畫識別符號取消動畫
    [layer removeAnimationForKey:@"moveUp"];
}

- (IBAction)dr:(id)sender {
    CABasicAnimation * downAndRight = [CABasicAnimation animationWithKeyPath:@"position"];
    downAndRight.duration = 5.0;
    //把c結構封裝成物件型別
    NSValue * endPoint = [NSValue valueWithCGPoint:CGPointMake(layer.position.x + 100, layer.position.y+100)];
    downAndRight.toValue = endPoint;
    [layer addAnimation:downAndRight forKey:@"downAndRight"];
}

- (IBAction)ul:(id)sender {
    CABasicAnimation * upAndLeft = [CABasicAnimation animationWithKeyPath:@"position"];
    upAndLeft.duration = 5.0;
    NSValue * endPoint = [NSValue valueWithCGPoint:CGPointMake(layer.position.x - 100, layer.position.y-100)];
    upAndLeft.toValue = endPoint;
    [layer addAnimation:upAndLeft forKey:@"upAndLeft"];
}

- (IBAction)stopall:(id)sender {
    //停止該圖層上所有動畫
    [layer removeAllAnimations];
}

效果如下:
CAAnimation類物件也可以設定它的委託物件,當動畫開始與結束時做自定義操作。CAAnimation的delegate屬性如下:
可以看到它與其他類的delegate屬性有些不同的是,它不需要遵循協議,只要委託物件中有如下函式即可: - (void)animationDidStart:(CAAnimation *)anim;
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
下面介紹CAPropertyAnimation的另一個子類CAKeyframeAnimation的用法。 CAKeyframeAnimation可以指定動畫執行的路徑,能夠製作出非常“不規則”的動畫。比如沿貝塞爾曲線的動畫。
下面就來看看如何來實現貝塞爾曲線動畫。 先看標頭檔案:
//
//  PathView.h
//  LearnAnimation
//
//  Created by zg on 15/6/7.
//  Copyright (c) 2015年 zg. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface PathView : UIView{
    CAShapeLayer * shapeLayer;
}

-(void)go;

@end

定義一個圓形圖層shapeLayer來執行動畫,定義一個執行方法go 再看實現檔案:
//
//  PathView.m
//  LearnAnimation
//
//  Created by zg on 15/6/7.
//  Copyright (c) 2015年 zg. All rights reserved.
//

#import "PathView.h"

@implementation PathView


// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    [self drawPath];
    [self drawCircle];
}

//定義角度轉弧度巨集
#define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/180)
//畫路徑
-(void)drawPath{
    UIBezierPath * path = [UIBezierPath bezierPath];
    path.lineCapStyle = kCGLineCapRound;//路徑端點圓狀
    [[UIColor blackColor]setStroke];
    [[UIColor blackColor]setFill];
    [path moveToPoint:CGPointMake(0, 100)];
    [path addCurveToPoint:CGPointMake(300, 100) controlPoint1:CGPointMake(75, 25) controlPoint2:CGPointMake(225, 175)];
    [path stroke];
    path.lineWidth = 3;
    [self setNeedsDisplay];
}

//畫圓形圖層
-(void)drawCircle{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:CGPointMake(4 , 100) radius:8 startAngle:0 endAngle:DEGREES_TO_RADIANS(360) clockwise:YES];
    [path closePath];
    shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = path.CGPath;
    [self.layer addSublayer:shapeLayer];
}

//執行動畫
-(void)go{
    CAKeyframeAnimation * pathAnim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    pathAnim.duration = 5;
    //生成可變路徑
    CGMutablePathRef mutablePath = CGPathCreateMutable();
    //座標點,相對於當前圖層pathLayer自身座標系
    CGPathMoveToPoint(mutablePath, NULL, 0 , 0);
    CGPathAddCurveToPoint(mutablePath, NULL, 75, -75, 225, 75, 300, 0);
    pathAnim.path = mutablePath;
    [shapeLayer addAnimation:pathAnim forKey:nil];

}

@end

主要解釋下實現函式go: 1、因為CAKeyframeAnimation是CAPropertyAnimation的子類,所以也會有animationWithKeyPath的動畫宣告方法。 2、CAKeyframeAnimation的path屬性可以指定動畫要執行的路徑。 3、要重點說明的是CGMutablePathRef路徑的座標點是相對於執行動畫的圖層shapeLayer自身座標系來計算的。 下面看效果:
三度空間的旋轉: layer有一個屬性叫sublayerTransform,是漸變屬性。通過CABasicAnimation動畫來改變sublayerTransform屬性,即可實現圖層的三度空間旋轉。 實現如下:
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self initSubLayer1];
    [self initSubLayer2];
    [self initSubLayer3];
    [self initPerspective];
}

-(void)initPerspective{
    //建立視點
    CATransform3D perspective = CATransform3DIdentity;
    int distance = 150;
    perspective.m34 = -1/distance;
    currentTransform = perspective;
    mContentView.layer.sublayerTransform = currentTransform;
}

-(void)initSubLayer1{
    subLayer1 = [CALayer layer];
    subLayer1.bounds = CGRectMake(0, 0, 100, 100);
    subLayer1.position = CGPointMake(140, 140);
    subLayer1.backgroundColor = [[UIColor blueColor]CGColor];
    subLayer1.cornerRadius = 10;//圓角半徑
    subLayer1.borderColor = [[UIColor blackColor]CGColor];
    subLayer1.borderWidth= 2;
    subLayer1.opacity = 0.5;
    [mContentView.layer addSublayer:subLayer1];
}

-(void)initSubLayer2{
    subLayer2 = [CALayer layer];
    subLayer2.bounds = CGRectMake(0, 0, 100, 100);
    subLayer2.position = CGPointMake(150, 150);
    subLayer2.backgroundColor = [[UIColor greenColor]CGColor];
    subLayer2.cornerRadius = 10;//圓角半徑
    subLayer2.borderColor = [[UIColor blackColor]CGColor];
    subLayer2.borderWidth= 2;
    subLayer2.opacity = 0.5;
    [mContentView.layer addSublayer:subLayer2];
}

-(void)initSubLayer3{
    subLayer3 = [CALayer layer];
    subLayer3.bounds = CGRectMake(0, 0, 100, 100);
    subLayer3.position = CGPointMake(160, 160);
    subLayer3.backgroundColor = [[UIColor redColor]CGColor];
    subLayer3.cornerRadius = 10;//圓角半徑
    subLayer3.borderColor = [[UIColor blackColor]CGColor];
    subLayer3.borderWidth= 2;
    subLayer3.opacity = 0.5;
    [mContentView.layer addSublayer:subLayer3];
}

- (IBAction)rotateZ:(id)sender {
    CABasicAnimation * rotateAnim = [CABasicAnimation animationWithKeyPath:@"sublayerTransform"];
    rotateAnim.fillMode = kCAFillModeForwards;
    rotateAnim.removedOnCompletion = NO;
    
    rotateAnim.duration = 3;
    CATransform3D rotateX3D = CATransform3DRotate(currentTransform, M_PI/6, 0, 0, 1);
    NSValue  * toValue = [NSValue valueWithCATransform3D:rotateX3D];
    rotateAnim.toValue = toValue;
    [mContentView.layer addAnimation:rotateAnim forKey:nil];
    currentTransform = rotateX3D;
}

當執行rotateZ函式可實現如下效果: