前言:iOS與MacOS的坐標系不同,iOS使用的是左手坐標系,坐標原點是在左上角,MacOS 使用的是右手坐標系,原點是在左下角。
簡單的動畫實現(xiàn):矩形平移動畫
- (void)viewDidLoad {
[super viewDidLoad];
//1.創(chuàng)建一個layer
CALayer *mylayer = [CALayer layer];
//2.設置layer屬性
mylayer.bounds = CGRectMake(0, 0, 50, 80);
mylayer.backgroundColor = [UIColor yellowColor].CGColor;
mylayer.position = CGPointMake(50, 50);
mylayer.anchorPoint = CGPointMake(0, 0);
mylayer.cornerRadius = 20;
//3.添加layer
[self.view.layer addSublayer:mylayer];
self.mylayer = mylayer;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//1.創(chuàng)建核心動畫(劇本)
CABasicAnimation *anima = [CABasicAnimation animation];
// 設置劇本具體動畫內(nèi)容
// 設置layer的position屬性,即平移
anima.keyPath = @"position";
anima.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
anima.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 300)];
// 設置動畫執(zhí)行完畢之后不刪除動畫
anima.removedOnCompletion = NO;
// 設置保存動畫的最新狀態(tài)
anima.fillMode = kCAFillModeForwards;
//2.添加核心動畫到layer(執(zhí)行劇本)
[self.mylayer addAnimation:anima forKey:nil];
}
這里有一個重要的知識點:position和anchorPoint,不懂的可以瀏覽這篇博客大頭青年,瞬間秒懂。這里就簡單講講我的理解:一個layer的位置frame是由position和anchorPoint共同決定的(不管layer之前的frame是多少都沒有影響)只要有一個改變了,那么layer的位置就會改變。第二了就是position和anchorPoint是不同坐標系的重合點,即指同一個點。
監(jiān)聽動畫的執(zhí)行過程,設置代理
在上方代碼的基礎上添加代理
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//1.創(chuàng)建核心動畫(劇本)
CABasicAnimation *anima = [CABasicAnimation animation];
// 設置劇本具體動畫內(nèi)容
// 設置layer的position屬性,即平移
anima.keyPath = @"position";
anima.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
anima.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 300)];
// 設置動畫執(zhí)行完畢之后不刪除動畫
anima.removedOnCompletion = NO;
// 設置保存動畫的最新狀態(tài)
anima.fillMode = kCAFillModeForwards;
// 設置代理
anima.delegate = self;
NSString *str = NSStringFromCGPoint(self.myLayer.position);
NSLog(@"執(zhí)行前:%@",str);
//2.添加核心動畫到layer(執(zhí)行劇本)
[self.mylayer addAnimation:anima forKey:nil];
}
- (void)animationDidStart:(CAAnimation*)anim{
NSLog(@"開始執(zhí)行動畫");
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
NSString *str = NSStringFromCGPoint(self.myLayer.position);
NSLog(@"執(zhí)行后:%@",str);
}
/*
輸出結果:
**2016-12-01 23:50:47.172 CAPropertyAnimationDemo[2829:99758] ****動畫執(zhí)行前:****{50, 50}**
**2016-12-01 23:50:47.173 CAPropertyAnimationDemo[2829:99758] ****動畫開始執(zhí)行了**
**2016-12-01 23:50:47.423 CAPropertyAnimationDemo[2829:99758] ****動畫執(zhí)行后:****{50, 50}**
*/
從上面的例子得出:即使保持了圖層在執(zhí)行完動畫后的狀態(tài),但是實質(zhì)上圖層的屬性值還是動畫執(zhí)行前的初始值,并沒有真正被改動。如上例中的position
CABasicAnimation 還有一組重要的屬性:autoreverses 和 repeatCount 。autoreverses 是否自動逆向執(zhí)行動畫到原先狀態(tài),執(zhí)行時間與正向動畫持續(xù)時間一致。repeatCount 是否重復動畫。這兩個屬性默認值是NO。
平移、縮放、旋轉
#import "ViewController.h"
@interface ViewController ()<CAAnimationDelegate>
@property (nonatomic,strong) CALayer *mylayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//1.創(chuàng)建一個layer
CALayer *mylayer = [CALayer layer];
//2.設置layer屬性
mylayer.bounds = CGRectMake(0, 0, 50, 80);
mylayer.backgroundColor = [UIColor yellowColor].CGColor;
mylayer.position = CGPointMake(50, 50);
mylayer.anchorPoint = CGPointMake(0, 0);
mylayer.cornerRadius = 20;
//3.添加layer
[self.view.layer addSublayer:mylayer];
self.mylayer = mylayer;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// [self keyPathWithPositionAnimation];
// [self keyPathWithBoundsAnimation];
// [self keyPathWithTransformAnimation];
[self positionByTransformAnimation];
}
#pragma mark - 平移動畫
- (void)keyPathWithPositionAnimation{
//1.創(chuàng)建核心動畫(劇本)
CABasicAnimation *anima = [CABasicAnimation animation];
// 設置劇本具體動畫內(nèi)容
// 設置layer的position屬性,即平移
// 注意:如果沒有設置起始位置"fromValue"的值,那么會從當前位置開始
anima.keyPath = @"position";
anima.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
anima.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 300)];
anima.duration = 2;
// 設置動畫執(zhí)行完畢之后不刪除動畫
anima.removedOnCompletion = NO;
// 設置保存動畫的最新狀態(tài)
anima.fillMode = kCAFillModeForwards;
anima.delegate = self;
NSString *string = NSStringFromCGRect(self.mylayer.frame);
NSLog(@"動畫執(zhí)行前:%@",string);
//2.添加核心動畫到layer(執(zhí)行劇本)
[self.mylayer addAnimation:anima forKey:nil];
}
#pragma mark - 縮放
- (void)keyPathWithBoundsAnimation{
//1.創(chuàng)建動畫
CABasicAnimation *anima = [CABasicAnimation animation];
anima.keyPath = @"bounds";
//1.1設置動畫執(zhí)行時間
anima.duration = 2.0;
//1.2設置保存動畫的最新狀態(tài)
anima.removedOnCompletion = NO;
anima.fillMode = kCAFillModeForwards;
//1.3修改屬性,執(zhí)行動畫
anima.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 200, 200)];
//2.0添加動畫到layer
[self.mylayer addAnimation:anima forKey:nil];
}
#pragma mark - 旋轉
- (void)keyPathWithTransformAnimation{
CABasicAnimation *anima = [CABasicAnimation animation];
anima.keyPath = @"transform";
anima.duration = 2.0;
anima.removedOnCompletion = NO;
anima.fillMode = kCAFillModeForwards;
anima.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2+M_PI_4, 1, 1, 0)];
[self.mylayer addAnimation:anima forKey:nil];
}
#pragma mark - 平移的第二種方式
- (void)positionByTransformAnimation{
CABasicAnimation *anima = [CABasicAnimation animation];
anima.keyPath = @"transform";
anima.duration = 2.0;
anima.removedOnCompletion = NO;
anima.fillMode = kCAFillModeForwards;
anima.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, 100, 1)];
[self.mylayer addAnimation:anima forKey:nil];
}
- (void)animationDidStart:(CAAnimation *)anim{
NSLog(@"動畫開始執(zhí)行了");
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
NSString *string = NSStringFromCGRect(self.mylayer.frame);
NSLog(@"動畫執(zhí)行后:%@",string);
}