一、關鍵幀動畫(CAKeyframeAnimation)
CAKeyframeAnimation和CABaseAnimation都屬於CAPropertyAnimatin的子類。CABaseAnimation只能從一個數值(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沒有設置的時候,各個關鍵幀的時間是平分的。
- values:值的數組
- path:值得路徑
- keyTimes:時間值(0,1)
timingFunctions:速度控制的數組 - calculationMode:動畫樣式
- kCAAnimationLinear 自定義控制動畫的時間(線性)可以設置keyTimes
- kCAAnimationDiscrete 離散動畫 沒有任何補間動畫 使用keytimes@[@0.3,@0.5,@1.0];
- kCAAnimationPaced 節奏動畫 自動計算動畫的運動時間
- kCAAnimationCubic 曲線動畫 需要設置timingFunctions
- kCAAnimationCubicPaced 節奏曲線動畫 自動計算
- rotationMode:旋轉的樣式
- kCAAnimationRotateAuto 自動
- kCAAnimationRotateAutoReverse 自動翻轉
第一種效果:
#import "ViewController.h"
@interface ViewController ()
//背景
@property (nonatomic, strong) CALayer *layer;
//花瓣
@property (nonatomic, strong) CALayer *petalLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
[self.view.layer addSublayer:self.layer];
[self.view.layer addSublayer:self.petalLayer];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self demo2:[[touches anyObject]locationInView:self.view]];
}
- (void)demo2:(CGPoint)toPoint{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:self.petalLayer.position];
[path addCurveToPoint:toPoint controlPoint1:CGPointMake(100, 100) controlPoint2:CGPointMake(52, 600)];
animation.path = path.CGPath;
animation.duration = 3;
animation.removedOnCompletion = NO;
animation.fillMode = kCAScrollBoth;
// 自動計算每個運動軌跡之間補間動畫的時間
animation.calculationMode = kCAAnimationCubicPaced;
animation.rotationMode = kCAAnimationRotateAuto;
[self.petalLayer addAnimation:animation forKey:@""];
}
- (CALayer *)petalLayer{
if (_petalLayer) {
return _petalLayer;
}
_petalLayer = [CALayer layer];
_petalLayer.position = CGPointMake(self.view.center.x, 50);
UIImage *image =[UIImage imageNamed:@"huaban-1"];
_petalLayer.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
_petalLayer.contents = (id)image.CGImage;
return _petalLayer;
}
- (CALayer *)layer{
if (_layer) {
return _layer;
}
_layer = [CALayer layer];
_layer.position = CGPointMake(self.view.center.x, self.view.center.y+100);
UIImage *image =[UIImage imageNamed:@"background"];
_layer.bounds = CGRectMake(0, 0, image.size.width/2, image.size.height/2);
_layer.contents = (id)image.CGImage;
return _layer;
}
@end
效果圖如下
第二種效果
// 關鍵幀動畫NO.2
#import "PatingView.h"
@implementation PatingView
- (UIBezierPath *)path{
if (_path!=nil) {
return _path;
}
_path = [UIBezierPath bezierPath];
return _path;
}
- (CALayer *)pointLayer{
if (_pointLayer) {
return _pointLayer;
}
_pointLayer = [CALayer layer];
_pointLayer.frame = CGRectMake(0, -20, 15, 15);
_pointLayer.cornerRadius = 15/2;
_pointLayer.backgroundColor = [UIColor colorWithRed:0.917 green:0.5309 blue:1.0 alpha:1.0].CGColor;
_pointLayer.shadowOpacity = 0.8;
_pointLayer.shadowRadius = 3;
_pointLayer.shadowColor = [UIColor colorWithRed:1.0 green:0.6648 blue:0.0006 alpha:1.0].CGColor;
[self.layer addSublayer:_pointLayer];
return _pointLayer;
}
/*
- (CALayer *)pointLayer{
if (_pointLayer) {
return _pointLayer;
}
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
replicatorLayer.frame = self.bounds;
replicatorLayer.instanceCount = 30;
replicatorLayer.instanceDelay = 0.5;
replicatorLayer.backgroundColor = [UIColor clearColor].CGColor;
[self.layer addSublayer:replicatorLayer];
_pointLayer = [CALayer layer];
_pointLayer.frame = CGRectMake(0, -20, 15, 15);
_pointLayer.cornerRadius = 15/2;
_pointLayer.backgroundColor = [UIColor colorWithRed:0.917 green:0.5309 blue:1.0 alpha:1.0].CGColor;
_pointLayer.shadowOpacity = 0.8;
_pointLayer.shadowRadius = 3;
_pointLayer.shadowColor = [UIColor colorWithRed:1.0 green:0.6648 blue:0.0006 alpha:1.0].CGColor;
[replicatorLayer addSublayer:_pointLayer];
return _pointLayer;
}
*/
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.path moveToPoint:[[touches anyObject] locationInView:self]];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.path addLineToPoint:[[touches anyObject] locationInView:self]];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[[UIColor colorWithRed:0.0444 green:0.4332 blue:1.0 alpha:1.0] set];
self.path.lineWidth = 5;
[self.path stroke];
}
- (void)start{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
animation.path = self.path.CGPath;
animation.duration = 5;
animation.repeatCount = HUGE;
[self.pointLayer addAnimation:animation forKey:@"move"];
}
@end
效果圖如下
二、CAAnimationGroup 動畫組,
動畫組可以讓動畫同時執行且不相互影響,他有一個數組animations:動畫的數組;動畫組設置的持續時間會影響到動畫組內部的動畫持久時間動畫組。
重要屬性
- animations:動畫的數組
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
[self.view.layer addSublayer:self.layer];
[self.view.layer addSublayer:self.petalLayer];
}
- (CALayer *)petalLayer{
if (_petalLayer) {
return _petalLayer;
}
_petalLayer = [CALayer layer];
_petalLayer.position = CGPointMake(self.view.center.x, 50);
UIImage *image =[UIImage imageNamed:@"huaban-1"];
_petalLayer.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
_petalLayer.contents = (id)image.CGImage;
return _petalLayer;
}
- (CALayer *)layer{
if (_layer) {
return _layer;
}
_layer = [CALayer layer];
_layer.position = CGPointMake(self.view.center.x, self.view.center.y+100);
UIImage *image =[UIImage imageNamed:@"background"];
_layer.bounds = CGRectMake(0, 0, image.size.width/2, image.size.height/2);
_layer.contents = (id)image.CGImage;
return _layer;
}
- (void)animationGroup:(CGPoint)endPoint{
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[[self move:endPoint], [self moveToBig]];
animationGroup.duration = 5;
/*
動畫組中設置的時間控制類屬性會影響到動畫組中設置的時間控制類屬性
在動畫組中統一設置媒體時間控制類屬性,入股需要單獨設置,動畫組中必須未設置相關屬性
1.CAMediaTiming媒體時間類協議
核心動畫關於時間類的控制 是遵守了CAMediaTiming中的協議內容
1.beginTime 動畫開始的時間 默認爲0
2.duration 動畫的持續時間 默認爲0 持續時間 受速度的影響 實際的動畫完成時間 = 持續時間/速度
3.speed 動畫播放的速度 默認爲1 速度設置成0 可以暫停動畫
speed 2秒 duration 60秒 動畫真正播放完成的時間 30秒
4.timeOffset 動畫播放時間的偏移量
5.repeatCount 動畫的循環次數 默認是0 只播放一次
6.repeatDuration 動畫循環的持續時間 只能設置其中的一個屬性 repeatCount/repeatDuration
7.autoreverses 是否以動畫的形式 返回到播放之前的狀態
8.fillMode 設置當前對象在非活動時間段的狀態
要想fillMode有效 需設置removedOnCompletion = NO
kCAFillModeForwards 當動畫結束後,layer會一直保持着動畫最後的狀態
kCAFillModeBackwards 立即進入動畫的初始狀態並等待動畫開始
kCAFillModeBoth 動畫加入後開始之前 layer處於動畫初始狀態 動畫結束後layer保持動畫最後的狀態
kCAFillModeRemoved 默認值 動畫結束後 layer會恢復到之前的狀態
*/
animationGroup.removedOnCompletion = NO;
animationGroup.fillMode = kCAFillModeBoth;
[self.petalLayer addAnimation:animationGroup forKey:@""];
}
/**
* 讓圖層移動的動畫
*
* @param endPoint 終點
*
* @return 移動的動畫
*/
- (CAKeyframeAnimation *)move:(CGPoint)endPoint{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
// 貝塞爾路徑
UIBezierPath *path = [UIBezierPath bezierPath];
// 設置起始點
[path moveToPoint:self.petalLayer.position];
/**
* 畫曲線
*
* @param ToPoint 終點
*
*controlPoint1、controlPoint2 控制點
*/
[path addCurveToPoint:endPoint controlPoint1:CGPointMake(50, 200) controlPoint2:CGPointMake(300, 400)];
animation.path = path.CGPath;
// kCAAnimationPaced 節奏動畫(不是勻速)
// kCAAnimationCubicPaced
animation.calculationMode = kCAAnimationCubicPaced;
return animation;
}
//放大
- (CABasicAnimation *)moveToBig{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@""];
animation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, CGRectGetWidth(self.petalLayer.bounds)*1.3, CGRectGetHeight(self.petalLayer.bounds)*1.3)];
return animation;
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self animationGroup:[[touches anyObject]locationInView:self.view]];
}
@end
效果圖如下
三、CATransition轉場動畫
屬性
官方文檔只提供了四種效果:
- kCATransitionFade 交叉淡化過渡
- kCATransitionMoveIn 新視圖移到舊視圖上面
- kCATransitionPush 新視圖把舊視圖推出去
- kCATransitionReveal 將舊視圖移開,顯示下面的新視圖
私有api
- pageCurl 向上翻一頁
- pageUnCurl 向下翻一頁
- rippleEffect 滴水效果
- suckEffect 收縮效果 如一塊布被抽走
- cube 立方體效果
- oglFlip 上下翻轉效果
- startProgress 開始的進度(0-1)(從那個開始)
endProgress 結束的進度(0-1)
注意:私有api,不建議開發者們使用。因爲蘋果公司不提供維護,並且有可能造成你的app審覈不通過
示例
#import "ViewController.h"
#import "NextViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)next:(id)sender {
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
NextViewController *nextVC = [storyBoard instantiateViewControllerWithIdentifier:@"NextViewController"];
CATransition *animation = [CATransition animation];
animation.type = @"rippleEffect";
animation.duration = 3;
[self.navigationController.view.layer addAnimation:animation forKey:@""];
[self.navigationController pushViewController:nextVC animated:YES];
}
@end
NextViewController.m中
#import "NextViewController.h"
@interface NextViewController ()
@end
@implementation NextViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
CATransition *animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.subtype = kCATransitionFromLeft;
animation.duration = 3;
[self.navigationController.view.layer addAnimation:animation forKey:@""];
[self.navigationController popViewControllerAnimated:NO];
}
其實,任何複雜的動畫其實都是由一個個簡單的動畫組裝而成的,只要我們善於分解和組裝,我們就能實現出滿意的效果。動畫其實也不是那麼難。