CALayer
CALayer負責視圖中顯示內容和動畫
UIView負責監聽和響應事件。在創建UIView對象時,UIView內部會自動創建一個圖層(CALayer對象),通過UIView的layer屬性可以訪問這個層。
當UIView需要顯示到屏幕上時,會調用
drawRect:
方法進行繪圖,并且會將所有內容繪制在自己的圖層上,繪圖完畢后,系統會將圖層拷貝到屏幕上,于是就完成UIView的顯示。每一個UIView內部都默認關聯著一個CALayer,我們可稱這個Layer為Root Layer(根層)。所有的非Root Layer,也就是手動創建的CALayer對象,都存在著隱式動畫
CALayer是定義在QuartzCore框架中的
CGImageRef、CGColorRef兩種數據類型是定義在CoreGraphics框架中的
UIColor、UIImage是定義在UIKit框架中的
QuartzCore框架和CoreGraphics框架是可以跨平臺使用的,在iOS和Mac OS X上都能使用(C 語言編寫)。但是UIKit只能在iOS中使用(Objective-C)
為了保證可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef 導入其他框架的方式: 選中項目, 在 General中找 Linked Frameworks and Libraries添加對應的框架
什么是隱式動畫?
當對非Root Layer的部分屬性進行修改時,默認會自動產生一些動畫效果 而這些屬性稱為Animatable Properties(可動畫屬性)
列舉幾個常見的Animatable Properties:
bounds:用于設置CALayer的寬度和高度。修改這個屬性會產生縮放動畫
backgroundColor:用于設置CALayer的背景色。修改這個屬性會產生背景色的漸變動畫
position:用于設置CALayer的位置。修改這個屬性會產生平移動畫
可通過動畫事務CATransaction關閉默認的隱式動畫效果
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.myView.layer.position = CGPointMake(10, 10);
[CATransaction commit];
UIView和CALayer的選擇
- 通過CALayer,就能做出跟UIImageView一樣的界面效果
既然CALayer和UIView都能實現相同的顯示效果,那究竟該選擇誰好呢?
其實,對比CALayer,UIView多了一個事件處理的功能。也就是說,CALayer不能處理用戶的觸摸事件,而UIView可以。所以,如果顯示出來的東西需要跟用戶進行交互的話,用UIView;如果不需要跟用戶進行交互,用UIView或者CALayer都可以 當然,CALayer的性能會高一些,因為它少了事件處理的功能,更加輕量級
- 注:UIView本身不具備顯示的功能,是它內部的層才有顯示功能。
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView* redView = [[UIView alloc] init];
redView.frame = CGRectMake(100, 100, 100, 100);
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
// 1>邊框
redView.layer.borderWidth = 10; // 邊框的寬度
redView.layer.borderColor = [UIColor whiteColor].CGColor; // 邊框的顏色
// 2>陰影
redView.layer.shadowOffset = CGSizeMake(50, 50); // 偏移量
redView.layer.shadowColor = [UIColor blueColor].CGColor; // 顏色
redView.layer.shadowOpacity = 1; // 透明度 (如果要顯示 一定要加)
redView.layer.shadowRadius = 50; // 陰影的圓角半徑
// 3>圓角
redView.layer.cornerRadius = 50;
redView.layer.masksToBounds = YES;
// 4>bounds
redView.layer.bounds = CGRectMake(0, 0, 200, 200);
// 5>postion屬性和view.center的關系 默認
redView.layer.position = CGPointMake(100, 100);
// 6>設置內容(圖片)
redView.layer.contents = (__bridge id)([UIImage imageNamed:@"me"].CGImage);
}
CALayer的transform屬性
// 旋轉
self.layer.transform = CATransform3DRotate(self.layer.transform, M_PI_4, 0, 0, 1);
// 縮放 z軸無效果
self.layer.transform = CATransform3DScale(self.layer.transform, 1, 1, 0.5);
// 平移 z軸無效果
self.layer.transform = CATransform3DTranslate(self.layer.transform, 0, 0, 10);
核心動畫
- Core Animation:核心動畫,是一組非常強大的動畫處理API。
- Core Animation的動畫執行過程是在后臺執行的,不會阻塞主線程。Core Animation是直接作用在CALayer上的,并非UIView。
使用步驟:
1、創建動畫對象
2、設置動畫屬性
3、把動畫對象添加到某個CALayer對象上
4、需要停止動畫:可以調用remove方法移除動畫
- CAAnimation是所有動畫對象的父類,負責控制動畫的持續時間和速度,是個抽象類,不能直接使用,應該使用它具體的子類.
- 屬性解析:(紅色代表來自CAMediaTiming協議的屬性)
duration:動畫的持續時間
repeatCount:動畫的重復次數
repeatDuration:動畫的重復時間
removedOnCompletion:默認為YES,代表動畫執行完畢后就從圖層上移除,圖形會恢復到動畫執行前的狀態。如果想讓圖層保持顯示動畫執行后的狀態,那就設置為NO,不過還要設置fillMode為kCAFillModeForwards
fillMode:決定當前對象在非active時間段的行為.比如動畫開始之前,動畫結束之后
beginTime:可以用來設置動畫延遲執行時間,若想延遲2s,就設置為CACurrentMediaTime()+2,CACurrentMediaTime()為圖層的當前時間。
timingFunction:速度控制函數,控制動畫運行的節奏
基礎動畫(CABasicAnimation)
CAPropertyAnimation的子類
屬性解析:
fromValue:keyPath相應屬性的初始值
toValue:keyPath相應屬性的結束值隨著動畫的進行,在長度為duration的持續時間內,keyPath相應屬性的值從fromValue漸漸地變為toValue
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, weak) CALayer* layer;
@end
@implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView* redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
redView.frame = CGRectMake(100, 100, 100, 100);
[self.view addSubview:redView];
self.layer = redView.layer;
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{
// *1.基本動畫
// 1.創建動畫對象
CABasicAnimation* anim = [[CABasicAnimation alloc] init];
// 2.操作
anim.keyPath = @"position.x";
// anim.fromValue = @(10); // 從哪
// anim.toValue = @(300); // 到哪
anim.byValue = @(10); // 在自身的基礎上累加
// 不希望核心動畫回到原來的位置
anim.fillMode = kCAFillModeForwards;
anim.removedOnCompletion = NO;
// 3.添加動畫
[self.layer addAnimation:anim forKey:nil];
}
@end
關鍵幀動畫(CAKeyframeAnimation)
CApropertyAnimation的子類
跟CABasicAnimation的區別是:CABasicAnimation只能從一個數值(fromValue)變到另一個數值(toValue),而CAKeyframeAnimation會使用一個NSArray保存這些數值-
屬性解析:
values:就是上述的NSArray對象。里面的元素稱為”關鍵幀”(keyframe)。 動畫對象會在指定的時間(duration)內,依次顯示values數組中的每一個關鍵幀
path:可以設置一個CGPathRef\CGMutablePathRef,讓層跟著路徑移動。path只對CALayer的anchorPoint和position起作用。如果你設置了path,那么values將被忽略
keyTimes:可以為對應的關鍵幀指定對應的時間點,其取值范圍為0到1.0,keyTimes中的每一個時間值都對應values中的每一幀.當keyTimes沒有設置的時候,各個關鍵幀的時間是平分的
CABasicAnimation可看做是最多只有2個關鍵幀的CAKeyframeAnimation
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, weak) CALayer* layer;
@end
@implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView* redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
redView.frame = CGRectMake(100, 100, 20, 20);
[self.view addSubview:redView];
self.layer = redView.layer;
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{
// 1.創建動畫對象
CAKeyframeAnimation* anim = [[CAKeyframeAnimation alloc] init];
// 2.操作
anim.keyPath = @"position";
// 創建一個圓的路徑
UIBezierPath* path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, 160, 160)]; anim.path = path.CGPath;
// 設置時間
anim.duration = 3;
// 設置重復次數
anim.repeatCount = INT_MAX;
// 3.添加動畫
[self.layer addAnimation:anim forKey:nil];
}
轉場動畫(CATransition)
- CAAnimation的子類,用于做轉場動畫,能夠為層提供移出屏幕和移入屏幕的動畫效果。
- UINavigationController就是通過CATransition實現了將控制器的視圖推入屏幕的動畫效果
- 屬性解析:
type:動畫過渡類型
subtype:動畫過渡方向
startProgress:動畫起點(在整體動畫的百分比)
endProgress:動畫終點(在整體動畫的百分比)
#import "ViewController.h"
@interface ViewController()<UIGestureRecognizerDelegate>
@property (nonatomic, strong) UIImageView* imageView;
@property (nonatomic, assign) int index;
@end
@implementation ViewController
//懶加載創建并添加imageView到view上
-(UIImageView *)imageView{
if (_imageView == nil) {
// 獲取圖片
NSString* imageName = [NSString stringWithFormat:@"%d", self.index];
UIImage* image = [UIImage imageNamed:imageName];
//創建視圖控制器
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(40, 40, 300, 400)];
_imageView.image = image; //打開交互
_imageView.userInteractionEnabled = YES;
[self.view addSubview:_imageView];
}
return _imageView;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.index = 1;
[self addSwipe];
}
- (void)addSwipe{
//添加輕掃手勢
UISwipeGestureRecognizer* swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
UISwipeGestureRecognizer* swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
swipeRight.direction = UISwipeGestureRecognizerDirectionLeft;
[self.imageView addGestureRecognizer:swipeLeft];
[self.imageView addGestureRecognizer:swipeRight];
}
- (void)swipe:(UISwipeGestureRecognizer*)sender{
// 轉場動畫
// 1.創建動畫
CATransition* anim = [[CATransition alloc] init];
// 2.操作
anim.type = @"cameraIrisHollowOpen";
if (sender.direction == UISwipeGestureRecognizerDirectionLeft) {
anim.subtype = kCATransitionFromLeft;
self.index ++;
}else {
anim.subtype = kCATransitionFromRight;
self.index --;
}
if (self.index == 6) {
self.index = 1;
}
if (self.index == 0) {
self.index = 5;
}
self.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%d",self.index]];
[self.imageView.layer addAnimation:anim forKey:nil];
}
@end
組動畫(CAAnimationGroup)
CAAnimation的子類,可以保存一組動畫對象,將CAAnimationGroup對象加入層后,組中所有動畫對象可以同時并發運行
屬性解析:
animations:用來保存一組動畫對象的NSArray
默認情況下,一組動畫對象是同時運行的,也可以通過設置動畫對象的beginTime屬性來更改動畫的開始時間。
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, weak) CALayer* layer;
@end
@implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView* redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
redView.frame = CGRectMake(100, 100, 20, 20);
[self.view addSubview:redView];
self.layer = redView.layer;
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event{
// 組動畫
// 1.創建動畫對象
CAAnimationGroup* group = [[CAAnimationGroup alloc] init];
// 2.操作
// *1.關鍵幀動畫 - 繞著圓的路徑轉
// ------
// 1.創建動畫對象
CAKeyframeAnimation* anim = [[CAKeyframeAnimation alloc] init];
// 2.操作
anim.keyPath = @"position";
// 創建一個圓的路徑
UIBezierPath* path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:80 startAngle:0 endAngle:2 * M_PI clockwise:1];
anim.path = path.CGPath;
// ------
// *2.基本動畫 - 自轉
// ------
// 1.創建動畫
CABasicAnimation* anim1 = [[CABasicAnimation alloc] init];
// 2.操作
anim1.keyPath = @"transform.rotation"; anim1.byValue = @(M_PI * 2 * 3);
// ------
group.animations = @[ anim, anim1 ];
// 設置事件
group.duration = 3;
// 設置次數
group.repeatCount = INT_MAX;
// 3.添加動畫
[self.layer addAnimation:group forKey:nil];
}
@end