iOS核心動畫筆記
- “小畫板程式”
完成”小畫板”程式。
下載地址:
http://git.oschina.net/changyou/mySmallPainter/repository/archive/master
git連結 :
https://git.oschina.net/changyou/mySmallPainter.git
2. CALayer介紹
2.1. CALayer
2.1 CALayer的常見屬性
- 設定控制器 view 的背景顏色, 更好的觀察
self.view.backgroundColor = [UIColor grayColor];
- 如何讓”控制元件”變的更好看? 通過操作控制元件的 CALayer, 修改控制元件的外觀。
- “陰影效果”
參考:
“`
// “陰影”效果(shadowColor、shadowOffset、shadowOpacity屬性需要同時設定後才可以看到)
// 設定”陰影”的顏色, 注意 UIKit 框架中的顏色不能直接設定給 CGColorRef
self.demoView.layer.shadowColor = [UIColor yellowColor].CGColor;
// 設定”陰影”的偏移
self.demoView.layer.shadowOffset = CGSizeMake(5, 5);
// 設定”陰影”的透明度(layer 的 opacity 相當於 view 的 alpha)
self.demoView.layer.shadowOpacity = 1.0;
// 設定”陰影”半徑
self.demoView.layer.shadowRadius = 10;
- "圓角效果"
- 畫圖解釋"圓角半徑"的含義
- 注意: 對於正方形來說, 當圓角半徑為邊長的一半的時候, 就是一個圓形
- 可以用這種方式對控制元件截圖
參考:
```
// 設定"圓角"效果
self.demoView.layer.cornerRadius = 20;
```
- 設定"邊框效果"
參考:
```
// 設定"邊框"效果
self.demoView.layer.borderColor = [UIColor whiteColor].CGColor;
self.demoView.layer.borderWidth = 2;
```
- 通過 UIImageView 實現"圖片裁剪"
參考:
```
- (void)viewDidLoad {
[super viewDidLoad];
// 設定控制器 view 的背景顏色, 更好的觀察
self.view.backgroundColor = [UIColor grayColor];
[self demoImageView];
// 設定"陰影"
// self.demoImageView.layer.shadowColor = [UIColor yellowColor].CGColor;
// self.demoImageView.layer.shadowRadius = 70;
// self.demoImageView.layer.shadowOffset = CGSizeMake(0, 0);
// self.demoImageView.layer.shadowOpacity = 1.0;
self.demoImageView.layer.cornerRadius = 50;
self.demoImageView.layer.borderWidth = 3;
self.demoImageView.layer.borderColor = [UIColor blueColor].CGColor;
// 注意: "陰影"效果" 和 "裁剪"不能同時應用
// CALayer 的 masksToBounds 類似於 UIView 的 clipsToBounds
self.demoImageView.layer.masksToBounds = YES;
// 儲存圖片
UIGraphicsBeginImageContextWithOptions(self.demoImageView.bounds.size, NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.demoImageView.layer renderInContext:ctx];
UIImage *imgIcon = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(imgIcon, nil, nil, nil);
}
- 2.2 “新建 CALayer”, 在 CALayer 中巢狀 CALayer(CALayer就像 UIView 一樣, 也可以實現巢狀)
1> 在控制器的 self.view 中新增一個普通的 layer
參考:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CALayer *layer = [[CALayer alloc] init];
// ------------------- 設定位置大小 ---------------------
// 方式一: 直接設定 frame
// layer.frame = CGRectMake(50, 50, 200, 200);
// 方式二:
// 先設定大小
layer.bounds = CGRectMake(0, 0, 100, 100);
// 再設定位置(預設情況下 position 指的是 center。)
layer.position = CGPointMake(150, 150);
// ------------------- 設定位置大小 ---------------------
layer.backgroundColor = [UIColor redColor].CGColor;
layer.opacity = 0.7;
[self.view.layer addSublayer:layer];
}
2> 在控制器的 view 中新增一個能顯示圖片的 layer
- 思路:
* 向普通的自定義的 layer 中設定內容即可。設定 layer.contents屬性。
* 檢視 layer.contents屬性的介紹
參考:
“`
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CALayer *layer = [[CALayer alloc] init];
// ——————- 設定位置大小 ———————
// 方式一: 直接設定 frame
// layer.frame = CGRectMake(50, 50, 200, 200);
// 方式二:
// 先設定大小
layer.bounds = CGRectMake(0, 0, 100, 100);
// 再設定位置(預設情況下 position 指的是 center。)
layer.position = CGPointMake(150, 150);
// ——————- 設定位置大小 ———————
layer.backgroundColor = [UIColor redColor].CGColor;
layer.opacity = 1.0;
UIImage *imgBg = [UIImage imageNamed:@”header_home”];
// UIKit 中使用的是 Foundation 框架, 而 Foundation 框架又使用的是 Core Foundation 框架
// Core Foundation 框架都是 C 語言的, 一般凡是 Core Xxxx 的框架都是 C 語言的。
// __bridge 型別 表示式, 的作用一般就是把 Core Foundation 中的資料型別轉換成 Foundation 中的型別, 橋接的時候也會設定到一些所有權的轉換等。
layer.contents = (__bridge id)(imgBg.CGImage);
[self.view.layer addSublayer:layer];
}
3> CALayer的"可動畫屬性"
- 凡是文件中有"Animatable"字樣的屬性都是可動畫屬性
- 可動畫屬性就是說: 只要設定了屬性(改變了屬性), 會自動使用畫的方式來執行。
// 通過position 修改 位置
- 案例: 在 touchesBegan: 方法中, 獲取當前觸控點的位置, 然後設定 layer的 position為這個觸控點。
* 效果: 設定完畢 position後, 自動會以動畫的方式來執行。(可動畫屬性)
參考:
```
@interface ViewController ()
@property (nonatomic, weak) CALayer *myLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CALayer *layer = [[CALayer alloc] init];
self.myLayer = layer;
// ------------------- 設定位置大小 ---------------------
// 方式一: 直接設定 frame
// layer.frame = CGRectMake(50, 50, 200, 200);
// 方式二:
// 先設定大小
layer.bounds = CGRectMake(0, 0, 100, 100);
// 再設定位置(預設情況下 position 指的是 center。)
layer.position = CGPointMake(150, 150);
// ------------------- 設定位置大小 ---------------------
layer.backgroundColor = [UIColor redColor].CGColor;
layer.opacity = 1.0;
UIImage *imgBg = [UIImage imageNamed:@"header_home"];
// UIKit 中使用的是 Foundation 框架, 而 Foundation 框架又使用的是 Core Foundation 框架
// Core Foundation 框架都是 C 語言的, 一般凡是 Core Xxxx 的框架都是 C 語言的。
// __bridge 型別 表示式, 的作用一般就是把 Core Foundation 中的資料型別轉換成 Foundation 中的型別, 橋接的時候也會設定到一些所有權的轉換等。
layer.contents = (__bridge id)(imgBg.CGImage);
[self.view.layer addSublayer:layer];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint point = [touch locationInView:touch.view];
self.myLayer.position = point;
}
@end
總結: iOS 中的動畫都是”屬性動畫”, 只要修改 layer的動畫屬性, 即可實現動畫。聯想之前的[UIView animateWithDuration:]動畫方法。
// 通過 transform 屬性進行形變
- 案例: 通過 CALayer的 transform屬性實現”旋轉”、”縮放”、”平移”
1> 縮放:
參考:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint point = [touch locationInView:touch.view];
// 設定 layer 的位置(預設 position 表示中心點的位置)
self.myLayer.position = point;
// 縮放(生成一個0.6~ 1.0之間的隨機數)
// CGFloat scale = (arc4random_uniform(5) + 1) / 10.0 + 0.5; //0.5;
// self.myLayer.transform = CATransform3DMakeScale(scale, scale, 0);
// 旋轉
CGFloat rotate = arc4random_uniform(M_PI * 2);
self.myLayer.transform = CATransform3DMakeRotation(rotate, 0, 5, 0);
}
2> 旋轉
* 介紹 x, y, z 軸
參考:
從 layer 的中心點到 給定的座標點之間連一條線, 然後以這個線為中心軸, 開始旋轉
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint point = [touch locationInView:touch.view];
// 設定 layer 的位置(預設 position 表示中心點的位置)
self.myLayer.position = point;
// 縮放(生成一個0.6~ 1.0之間的隨機數)
CGFloat scale = (arc4random_uniform(5) + 1) / 10.0 + 0.5; //0.5;
self.myLayer.transform = CATransform3DMakeScale(scale, scale, 0);
// 旋轉
CGFloat rotate = arc4random_uniform(M_PI * 2);
self.myLayer.transform = CATransform3DMakeRotation(rotate, 0, 0, 10);
}
// 問題:在 touchesBegan 方法中先後指定了 transform, 這樣後指定的 transform 會覆蓋前面的 transform, 所以現在的效果是隻旋轉,不縮放了。
// 解決: 通過 kvc 解決:
參考解決辦法:
“`
// 縮放(生成一個0.6~ 1.0之間的隨機數)
CGFloat scale = (arc4random_uniform(5) + 1) / 10.0 + 0.5;
//self.myLayer.transform = CATransform3DMakeScale(scale, scale, 0);
[self.myLayer setValue:@(scale) forKeyPath:@”transform.scale”];
// 旋轉
CGFloat rotate = arc4random_uniform(M_PI * 2);
//self.myLayer.transform = CATransform3DMakeRotation(rotate, 0, 0, 10);
[self.myLayer setValue:@(rotate) forKeyPath:@”transform.rotation”];
struct CATransform3D
{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
};
struct CGAffineTransform {
CGFloat a, b, c, d;
CGFloat tx, ty;
};
// 圓角,透明度,邊框
參考:
```
// 圓角
self.myLayer.cornerRadius = 20;
self.myLayer.masksToBounds = YES;
// 透明度
self.myLayer.opacity = 0.5;
// 設定邊框
self.myLayer.borderColor = [UIColor redColor].CGColor;
self.myLayer.borderWidth = 5;
Quartz Core框架不需要匯入, 已經預設匯入了
- CALayer的 position屬性和 anchorPoint屬性介紹
- anchorPoint是一個 CGPoint型別, 每個值都是一個0~1之間的值
- 動畫屬性(隱式動畫)需要注意點:
- 每一個UIView內部都預設關聯著一個CALayer, 我們可稱這個Layer為Root Layer(根層)
- 所有的非Root Layer, 也就是手動建立的CALayer物件, 都存在著隱式動畫。 root layer 是沒有隱式動畫的
- 關閉隱式動畫
參考;
可以通過動畫事務(CATransaction)關閉預設的隱式動畫效果
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.myview.layer.position = CGPointMake(10, 10);
[CATransaction commit];
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CALayer *layer = [[CALayer alloc] init];
layer.backgroundColor = [UIColor blueColor].CGColor;
layer.bounds = CGRectMake(0, 0, 100, 100);
layer.position = CGPointMake(200, 200);
[self.view.layer addSublayer:layer];
self.blueLayer = layer;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint point = [touch locationInView:touch.view];
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.blueLayer.position = point;
[CATransaction commit];
}
附:
- 案例練習:(時鐘動畫)
- 使用 CALayer的”定位點(錨點)”實現一個時鐘動畫(通過 UIView 來實現,目的是為了說明控制元件的 center 其實就是 CALayer的 position, 通過修改了 position其實就修改了 center 的含義了)
- 注意: 在使用 Quartz2D 繪圖的時候, 對繪圖上下文的旋轉是對座標系的旋轉, 通過 UI 控制元件的 transform 對控制元件做旋轉是按照 Center 來旋轉的。
注意: 控制元件的 center 屬性, 其實就是對應的 CALayer的 postion。所以控制元件的 center並不是永遠表示控制元件的中心點。
解決不準確的問題:
• 通過 NSTimer 實現的動畫可能造成卡頓、不連貫的情況(NSTimer 不準確)
• CADisplayLink 表示”顯示連線”, 與顯示器的重新整理頻率相關。
• 顯示器每秒鐘重新整理60次(60HZ)(電視新聞上拍的電腦顯示器就不清楚,原因重新整理頻率不一樣)
• 通過 CADisplayLink 來解決
參考程式碼:
// 核心程式碼
CADisplayLink *timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(moveSecond)];
[timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 建立錶盤
UIView *clockView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 150, 150)];
clockView.backgroundColor = [UIColor blueColor];
clockView.center = CGPointMake(self.view.bounds.size.width * 0.5, self.view.bounds.size.height * 0.5);
[self.view addSubview:clockView];
self.clockView = clockView;
// 2. 建立秒針
UIView *secondView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 50)];
secondView.backgroundColor = [UIColor redColor];
secondView.layer.anchorPoint = CGPointMake(0.5, 1);
secondView.center = clockView.center;
[self.view addSubview:secondView];
self.secondView = secondView;
[self moveSecond];
// 3. 啟動一個計時器, 每隔一秒鐘計算一下當前秒針的位置, 然後做一次哦旋轉操作
// [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(moveSecond) userInfo:nil repeats:YES];
CADisplayLink *timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(moveSecond)];
[timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)moveSecond
{
// 1. 計算當前的秒數
NSDate *nowDate = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger seconds = [calendar component:NSCalendarUnitSecond fromDate:nowDate];
// 2. 計算每一秒的弧度
CGFloat rotation = M_PI * 2 / 60;
// 3. 用每一秒的弧度 * 秒數 , 計算出本次要旋轉的弧度
rotation = seconds * rotation;
// 4. 旋轉秒針
self.secondView.transform = CGAffineTransformMakeRotation(rotation);
}
// 每次觸控一次螢幕秒針轉一次
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGFloat rotation = M_PI * 2 / 60;
self.secondView.transform = CGAffineTransformRotate(self.secondView.transform, rotation);
}
@end
核心動畫
屬性動畫
1> 基本動畫(只有兩幀的動畫)
2> 關鍵幀動畫組動畫
轉場動畫(場景轉換)
2.1 基本動畫: 位移
案例: 觸控螢幕, 設定指定的 view 的 layer的 position值
參考:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 1. 建立動畫物件
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
// 預設動畫時間是0.25秒
animation.duration = 2.0;
// 2. 設定動畫屬性值
animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(200, 30)];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(240, 500)];
// 3. 將動畫新增到對應的layer 中
[self.blueView.layer addAnimation:animation forKey:@"animation1"];
}
- (void)viewDidLoad {
[super viewDidLoad];
UIView *blueView = [[UIView alloc] initWithFrame:CGRectMake(50, 150, 100, 100)];
blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueView];
self.blueView = blueView;
}
- 問題:
1> 動畫太快, 預設時間是0.25秒, 通過 duration 屬性修改
2> 動畫執行完畢以後回到了起始的位置。
• 原因:
• 核心動畫的本質是在後臺移動圖層中的內容, 控制元件本身的 frame 沒有發生改變。
• 所以看到動畫執行完畢後, 又回到了原來的位置
• 通過設定動畫代理來觀察動畫執行完畢後控制元件的 frame 值, layer 的 Frame 值, layer 的 position 值, 都是沒有變化的
• 解決:
解決1:當動畫執行完畢以後, 手動設定控制元件的位置。在動畫的代理方法(動畫結束的時候設定控制元件的 center)
//self.blueView.center = CGPointMake(300, 50);
注意: 不指定 fromValue 的情況下, 如果直接在新增完畢動畫後, 設定控制元件的 center = 最終的終點有問題!!!所以不要在新增完動畫以後直接設定 center 為最終的終點, 而要放到代理方法中。
解決2:
動畫執行完畢後不要刪除動畫物件
設定 fillMode
// 當動畫執行完畢後不要刪除動畫物件
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
缺點: 無法與使用者互動, 因為 frame 就沒變
3> 介紹隱式代理
4> 不指定 fromValue 就是從當前位置開始動畫
5> 注意:
- 如果每次執行完畢動畫都設定控制元件的 frame 為最終的 frame, 那麼在連續多次點選的時候, 每次控制元件都要從上次結束出開始動畫, 效果不好
- 如果通過”動畫執行完畢後不要刪除動畫物件”, 動畫比較流暢, 但是控制元件的 frame 始終沒有變化, 將來可能會影響與使用者互動
參考:
“`
- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event
{
// 1. 建立動畫物件
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@”position”];
// 預設動畫時間是0.25秒
animation.duration = 2.0;
// 設定動畫代理
animation.delegate = self;
// 當動畫執行完畢後不要刪除動畫物件
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
// 2. 設定動畫屬性值
//animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(200, 30)];
animation.fromValue = [NSValue valueWithCGPoint:self.blueView.center];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(240, 500)];
// 3. 將動畫新增到對應的layer 中
[self.blueView.layer addAnimation:animation forKey:@”animation1”];
// 動畫執行完畢後設定控制元件的 center
//NSLog(@”★”);
//self.blueView.center = CGPointMake(300, 50);
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
NSLog(@”%@—-“, NSStringFromCGRect(self.blueView.frame));
NSLog(@”========%@”, NSStringFromCGRect(self.blueView.layer.frame));
NSLog(@”========%@”, NSStringFromCGPoint(self.blueView.layer.position));
//self.blueView.center = CGPointMake(300, 50);
}
//——————– 參考—————–
// 1. 建立動畫物件
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@”position”];
// 預設動畫時間是0.25秒
animation.duration = 1.0;
// 設定動畫代理
animation.delegate = self;
// 當動畫執行完畢後不要刪除動畫物件
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
// 2. 設定動畫屬性值
//animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(200, 30)];
// animation.fromValue = [NSValue valueWithCGPoint:self.blueView.center];
//animation.toValue = [NSValue valueWithCGPoint:CGPointMake(240, 500)];
animation.toValue = [NSValue valueWithCGPoint:location];
// 3. 將動畫新增到對應的layer 中
// 這樣每次會新增一個新的動畫
//self.blueView.layer addAnimation:animation forKey:nil] ;
// 注意: 如果下面的 key 指定了一個寫死的 key,@”animation100”,這樣不會每次都新增一個新的動畫了。
[self.blueView.layer addAnimation:animation forKey:@”animation100”];
// 動畫執行完畢後設定控制元件的 center
//NSLog(@”★”);
//self.blueView.center = CGPointMake(300, 50);
2.2 基本動畫: 縮放動畫
參考:
```
// 縮放動畫
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 建立動畫物件
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
// 設定動畫屬性
anim.fromValue = @(1.0f);
anim.toValue = @(0.7f);
// 設定重複次數
anim.repeatCount = 10;
// 將動畫物件新增到 layer 中
[self.blueView.layer addAnimation:anim forKey:nil];
}
2.3 基本動畫: 旋轉動畫
參考
// 旋轉動畫
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
anim.duration = 3;
anim.repeatCount = CGFLOAT_MAX;
// 不要每次都設定起始度數
//anim.fromValue = @(0);
anim.toValue = @(M_PI * 2);
[self.blueView.layer addAnimation:anim forKey:nil];
}
- 注意: 如果 [self.blueView.layer addAnimation:anim forKey:nil];沒有指定 forKey, 那麼每次都會新增一個新動畫, 會越來越快
- 解決:
參考:
“`
- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event
{
// 判斷如果已經有動畫物件了, 就不再新增了
if ([self.blueView.layer animationForKey:@”anim1”] != nil) {
return;
}
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@”transform.rotation”];
anim.duration = 3;
anim.repeatCount = CGFLOAT_MAX;
// 不要每次都設定起始度數
//anim.fromValue = @(0);
anim.toValue = @(M_PI * 2);
[self.blueView.layer addAnimation:anim forKey:@”anim1”];
}
* 注意: 如果當動畫正在執行的時候, 將程式退出到後臺, 那麼當程式再次進入前臺的時候就不執行了。
* 原因: 因為再次進入前臺後動畫已經被刪除了。
* 解決1: anim.removedOnCompletion = NO;
* 問題: 當雙擊 home 鍵的時候, 動畫不會暫停。
* 解決:
參考:
```
// 暫停
- (void)applicationWillResignActive:(UIApplication *)application {
ViewController *vc = (ViewController *)self.window.rootViewController;
[vc pause];
}
// 恢復
- (void)applicationDidBecomeActive:(UIApplication *)application {
ViewController *vc = (ViewController *)self.window.rootViewController;
[vc resume];
}
2.4 關鍵幀動畫
- 設定 values 屬性
參考:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
anim.duration = 3;
anim.removedOnCompletion = NO;
CGPoint p1 = CGPointMake(10, 10);
CGPoint p2 = CGPointMake(10, 110);
CGPoint p3 = CGPointMake(110, 110);
CGPoint p4 = CGPointMake(110, 10);
CGPoint p5 = CGPointMake(10, 10);
anim.values = @[[NSValue valueWithCGPoint:p1], [NSValue valueWithCGPoint:p2], [NSValue valueWithCGPoint:p3], [NSValue valueWithCGPoint:p4],[NSValue valueWithCGPoint:p5]];
[self.blueView.layer addAnimation:anim forKey:nil];
}
- 設定 path 屬性
參考:
“`
- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event
{
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@”position”];
anim.duration = 3;
anim.removedOnCompletion = NO;
anim.fillMode = kCAFillModeForwards;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 150, 150)];
anim.path = path.CGPath;
[self.blueView.layer addAnimation:anim forKey:nil];
}
- 模擬"app 抖動"
* 思路: 通過設定左右旋轉實現
參考:
- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event
{
if ([self.blueView.layer animationForKey:@”shake”]) {
return;
}
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@”transform.rotation”];
anim.values = @[@(-M_PI / 36), @(M_PI / 36), @(-M_PI / 36)];
anim.duration = 0.15;
anim.repeatCount = CGFLOAT_MAX;
[self.blueView.layer addAnimation:anim forKey:@”shake”];
}
- 組動畫
參考:
// 動畫組, 組動畫
- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event
{
UITouch *touch = touches.anyObject;
CGPoint location = [touch locationInView:touch.view];
CAAnimationGroup *groupAnim = [[CAAnimationGroup alloc] init];
// 位移
CABasicAnimation *anim1 = [CABasicAnimation animationWithKeyPath:@”position”];
anim1.toValue = [NSValue valueWithCGPoint:location];
// 縮放
CABasicAnimation *anim2 = [CABasicAnimation animationWithKeyPath:@”transform.scale”];
anim2.toValue = @(0.3);
// 旋轉
CABasicAnimation *anim3 = [CABasicAnimation animationWithKeyPath:@”transform.rotation”];
anim3.toValue = @(M_PI * 8);
// 關鍵幀動畫
CAKeyframeAnimation *anim4 = [CAKeyframeAnimation animationWithKeyPath:@”position”];
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(180, 150, 150, 150)];
anim4.path = path.CGPath;
groupAnim.animations = @[anim1, anim2, anim3, anim4];
groupAnim.duration = 1.0;
groupAnim.repeatCount = CGFLOAT_MAX;
[self.blueView.layer addAnimation:groupAnim forKey:nil];
}
“`
轉場動畫
案例: 通過在 view 中放一個圖片框, 從”控制元件庫”中拖拽兩個”輕掃手勢”(拖到哪個控制元件上, 就表示應用到了哪個控制元件上, 開啟看 storyboard 中的 xml 檔案),然後為”輕掃手勢”拖線連線處理程式, 在處理程式中實現”轉場動畫”。
參考:
“`
- (IBAction)swipeLeft:(UISwipeGestureRecognizer *)sender {
// 建立一個轉場動畫物件
CATransition *anim = [[CATransition alloc] init];
// 設定過度型別
anim.type = @”cube”;
if (sender.direction == UISwipeGestureRecognizerDirectionLeft) {
anim.subtype = kCATransitionFromRight;
} else {
anim.subtype = kCATransitionFromLeft;
}
[self.imgViewIcon.layer addAnimation:anim forKey:nil];
}//——————————————————-
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imgViewIcon;
@property (nonatomic, assign) int index;
@end
@implementation ViewController
- (IBAction)swipeLeft:(UISwipeGestureRecognizer *)sender {
// 建立一個轉場動畫物件
CATransition *anim = [[CATransition alloc] init];
// 設定過度型別
anim.type = @”cube”;
if (sender.direction == UISwipeGestureRecognizerDirectionLeft) {
anim.subtype = kCATransitionFromRight;
self.index–;
} else {
anim.subtype = kCATransitionFromLeft;
self.index++;
}
if (self.index < 0) {
self.index = 4;
}
if (self.index > 4) {
self.index = 0;
}
NSString *imgName = [NSString stringWithFormat:@”%d”, (self.index + 1)];
self.imgViewIcon.image = [UIImage imageNamed:imgName];
[self.imgViewIcon.layer addAnimation:anim forKey:nil];
}
//————– 通過 uiview 實現轉場動畫———–
- (IBAction)swipeLeft:(UISwipeGestureRecognizer *)sender {
UIViewAnimationOptions option;
if (sender.direction == UISwipeGestureRecognizerDirectionLeft) {
option = UIViewAnimationOptionTransitionCurlUp;
self.index–;
} else {
option = UIViewAnimationOptionTransitionCurlDown;
self.index++;
}
if (self.index < 0) {
self.index = 4;
}
if (self.index > 4) {
self.index = 0;
}
NSString *imgName = [NSString stringWithFormat:@”%d”, (self.index + 1)];
self.imgViewIcon.image = [UIImage imageNamed:imgName];
[UIView transitionWithView:self.view duration:1.0 options:option animations:^{
// 在轉場動畫的過程中還可以執行其他的動畫
} completion:^(BOOL finished) {
// 動畫執行完畢後要做的事情
}];
}
“`
相關文章
- iOS 核心動畫高階技巧 - 1iOS動畫
- iOS 動畫iOS動畫
- QT學習筆記4(動畫)QT筆記動畫
- IOS動畫使用iOS動畫
- iOS 動畫之Spring動畫、Block動畫、GIF圖iOS動畫SpringBloC
- iOS動畫專題·UIView二維形變動畫與CAAnimation核心動畫(transform動畫,基礎,關鍵幀,組動畫,路徑動畫,貝塞爾曲線)iOS動畫UIViewORM
- iOS動畫全面解析iOS動畫
- iOS UIView基本動畫iOSUIView動畫
- iOS 動畫技巧 (一)iOS動畫
- 醒酒菜:動畫圖解核心記憶體區--堆動畫圖解記憶體
- 核心動畫(Core Animation Programming)動畫
- 【Flutter 實戰】動畫核心Flutter動畫
- Linux 核心配置筆記Linux筆記
- iOS 關鍵幀動畫iOS動畫
- iOS 動畫之CoreAnimation(CALayer)iOS動畫
- 聊聊iOS中的動畫iOS動畫
- iOS實現字串動畫iOS字串動畫
- 2019ios筆記iOS筆記
- IOS筆記之字串iOS筆記字串
- IOS筆記之字典iOS筆記
- 筆記-iOS應用程式的啟動過程筆記iOS
- iOS學習筆記01 APP啟動相關iOS筆記APP
- 核心動畫程式設計(一)動畫程式設計
- 核心動畫程式設計(二)動畫程式設計
- EOL 筆記:核心類解析筆記
- JVM核心學習筆記JVM筆記
- iOS動畫系列之四:基礎動畫之平移篇iOS動畫
- 系統學習iOS動畫之一:檢視動畫iOS動畫
- 系統學習iOS動畫之三:圖層動畫iOS動畫
- iOS 動畫 - 窗景篇(二)iOS動畫
- Realm ios踩坑筆記iOS筆記
- iOS Block學習筆記iOSBloC筆記
- IOS筆記之陣列iOS筆記陣列
- 系統學習iOS動畫之六:3D動畫iOS動畫3D
- iOS動畫系列之七:實現類似Twitter的啟動動畫iOS動畫
- Android 學習筆記核心篇Android筆記
- Linux核心自旋鎖使用筆記Linux筆記
- iOS 動畫基礎總結篇iOS動畫
- iOS動畫-擴散波紋效果iOS動畫