上一篇iOS核心動(dòng)畫詳解1說的很清楚了,那么下面詳細(xì)介紹。
那么這里,將介紹上面所提到的7個(gè)類和1個(gè)協(xié)議具體的細(xì)節(jié)。
1:CAMediaTiming協(xié)議
CAMediaTiming 協(xié)議中定義了時(shí)間,速度,重復(fù)次數(shù)等。屬性定義如下:
beginTime-> 用來設(shè)置動(dòng)畫延時(shí),若想延遲1秒,就設(shè)置為CACurrentMediaTime()+1,其中CACurrentMediaTime()為圖層當(dāng)前時(shí)間。duration-> 動(dòng)畫的持續(xù)時(shí)間。speed-> 動(dòng)畫速率,決定動(dòng)畫時(shí)間的倍率。當(dāng)speed為2時(shí),動(dòng)畫時(shí)間為設(shè)置的duration的1/2。timeOffset-> 動(dòng)畫時(shí)間偏移量。比如設(shè)置動(dòng)畫時(shí)長(zhǎng)為3秒,當(dāng)設(shè)置timeOffset為1.5時(shí),當(dāng)前動(dòng)畫會(huì)從中間位置開始,并在到達(dá)指定位置時(shí),走完之前跳過的前半段動(dòng)畫。repeatCount-> 動(dòng)畫的重復(fù)次數(shù)。repeatDuration-> 動(dòng)畫的重復(fù)時(shí)間。autoreverses-> 動(dòng)畫由初始值到最終值后,是否反過來回到初始值的動(dòng)畫。如果設(shè)置為YES,就意味著動(dòng)畫完成后會(huì)以動(dòng)畫的形式回到初始值。fillMode-> 決定當(dāng)前對(duì)象在非動(dòng)畫時(shí)間段的行為.比如動(dòng)畫開始之前,動(dòng)畫結(jié)束之后。
fillMode詳細(xì)說明:試想這樣一個(gè)問題:在beginTime非0(即動(dòng)畫未真正執(zhí)行之前),以及removeOnCompletion被設(shè)置為NO的動(dòng)畫結(jié)束時(shí),我們會(huì)遇到這樣一個(gè)問題:被設(shè)置動(dòng)畫的屬性應(yīng)該是什么值?
一種可能是屬性與動(dòng)畫沒被添加之前保持一致,還有一種可能是保持動(dòng)畫開始之前那一幀或者動(dòng)畫結(jié)束那一幀,這就是所謂的填充。
CAMediaTiming的fillMode用來控制填充效果,它是一個(gè)NSString類型,有四種常量可供使用:
kCAFillModeRemoved (default) NSString 默認(rèn)值,動(dòng)畫開始前和結(jié)束后,動(dòng)畫對(duì)圖層都沒有影響,圖層依然保持初始值
kCAFillModeForwards NSString 動(dòng)畫結(jié)束后,圖層一直保持動(dòng)畫后的最終狀態(tài)
kCAFillModeBackwards NSString 動(dòng)畫開始前,只要加入動(dòng)畫就會(huì)處于動(dòng)畫的初始狀態(tài)
kCAFillModeBoth NSString 綜合了kCAFillModeForwards與kCAFillModeBackwards特性;
(動(dòng)畫加入圖層到真正執(zhí)行動(dòng)畫的時(shí)間段里,圖層保持動(dòng)畫初始狀態(tài);動(dòng)畫結(jié)束之后保持動(dòng)畫最終狀態(tài))
其實(shí)不只是CAAnimation遵循CAMediaTiming協(xié)議,熟悉底層結(jié)構(gòu)的小伙伴們應(yīng)該知道CALayer也遵循這個(gè)協(xié)議,所有在一定程度上我們可以通過控制layer本身的協(xié)議屬性來控制動(dòng)畫節(jié)奏。
2:CAAnimation核心動(dòng)畫基礎(chǔ)類
CAAnimation核心動(dòng)畫基礎(chǔ)類,不能直接使用。除了CAMediaTiming協(xié)議中的方法,增加了CAAnimationDelegate的代理屬性等。關(guān)于它的定義如下:
@interface CAAnimation : NSObject<NSSecureCoding, NSCopying, CAMediaTiming, CAAction>
@property(nullable, strong) CAMediaTimingFunction *timingFunction;
@property(nullable, strong) id <CAAnimationDelegate> delegate;
@property(getter=isRemovedOnCompletion) BOOL removedOnCompletion;
@end
屬性如下:
timingFunction-> 動(dòng)畫緩沖屬性。動(dòng)畫實(shí)際上就是在一段時(shí)間內(nèi)隨著某個(gè)特定速率執(zhí)行變化的過程,現(xiàn)實(shí)中的任何物體都會(huì)在運(yùn)動(dòng)中經(jīng)歷加速或者減速的過程,而不是速度驟變;因此,CoreAnimation也內(nèi)嵌了一系列標(biāo)準(zhǔn)的緩沖函數(shù)來使動(dòng)畫看起來更平滑自然,這就是我們要說到的動(dòng)畫緩沖??刂苿?dòng)畫的節(jié)奏。系統(tǒng)提供的包括:kCAMediaTimingFunctionLinear(默認(rèn),勻速執(zhí)行動(dòng))kCAMediaTimingFunctionEaseIn(慢進(jìn)快出)kCAMediaTimingFunctionEaseOut(快進(jìn)慢出)kCAMediaTimingFunctionEaseInEaseOut(慢進(jìn)慢出,中間加速)kCAMediaTimingFunctionDefault(默認(rèn)),當(dāng)然也可通過自定義創(chuàng)建CAMediaTimingFunction。
注意:KCAMediaTimingFuncationDefault相比KCAMediaTimingFuncationEaseInEaseOut的加速和減速過程稍微有些慢,兩者區(qū)別很難察覺;可能蘋果也覺得它更適合用于隱式動(dòng)畫,就作為了隱式動(dòng)畫的默認(rèn)效果;但是創(chuàng)建顯式的CAAnimation時(shí),KCAMediaTimingFuncationLinear才是默認(rèn)效果而非KCAMediaTimingFuncationDefault;removedOnCompletion-> 是否讓圖層保持顯示動(dòng)畫執(zhí)行后的狀態(tài),默認(rèn)為YES,也就是動(dòng)畫執(zhí)行完畢后從涂層上移除,恢復(fù)到執(zhí)行前的狀態(tài),如果設(shè)置為NO,并且設(shè)置fillMode為kCAFillModeForwards,則保持動(dòng)畫執(zhí)行后的狀態(tài)。delegate -> 代理。
CAAnimation的delegate代理方法如下幾個(gè):
//動(dòng)畫開始時(shí)執(zhí)行的回調(diào)
- (void)animationDidStart:(CAAnimation *)anim;
//動(dòng)畫結(jié)束后執(zhí)行的回調(diào)
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
removedOnCompletion屬性默認(rèn)為YES,表示動(dòng)畫完成后就會(huì)從圖層上移除,圖層也會(huì)恢復(fù)到動(dòng)畫執(zhí)行前的狀態(tài);當(dāng)其修改為NO時(shí),那么圖層將會(huì)保持動(dòng)畫結(jié)束后的狀態(tài),此時(shí)的fillMode屬性也將生效;
另外,removedOnCompletion設(shè)置為NO時(shí),直到我們手動(dòng)移除動(dòng)畫,否則動(dòng)畫將不會(huì)自動(dòng)釋放;所以通常我們此時(shí)會(huì)給動(dòng)畫添加一個(gè)非空的鍵,這樣可以在不需要?jiǎng)赢嫷臅r(shí)候把它從圖層上移除;
3:CAPropertyAnimation 屬性動(dòng)畫
CAPropertyAnimation 是一個(gè)抽象類,不可直接使用。不能直接用于實(shí)現(xiàn)CALayer動(dòng)畫操作,但是它的類定義中增加用于設(shè)置CALayer可被實(shí)現(xiàn)動(dòng)畫的屬性keyPath。
方法 :+ (instancetype)animationWithKeyPath:(NSString *)path;該方法僅需要一個(gè)參數(shù),該參數(shù)只是一個(gè)字符串的值,指定CALayer的動(dòng)畫屬性名,該設(shè)置屬性動(dòng)畫控制CALayer的哪個(gè)動(dòng)畫屬性持續(xù)的改變。
屬性:具體如下:
keyPath-> CALayer的某個(gè)屬性名,并通過這個(gè)屬性的值進(jìn)行修改,達(dá)到相應(yīng)的動(dòng)畫效果。additive-> 屬性動(dòng)畫是否以當(dāng)前動(dòng)畫效果為基礎(chǔ),默認(rèn)為NO。cumulative-> 指定動(dòng)畫是否為累加效果,默認(rèn)為NO。valueFunction-> 此屬性配合CALayer的transform屬性使用。
CABasicAnimation基礎(chǔ)動(dòng)畫,通過keyPath對(duì)應(yīng)屬性進(jìn)行控制,需要設(shè)置fromValue以及toValue。添加屬性如下:fromValue-> keyPath相應(yīng)屬性的初始值。toValue-> keyPath相應(yīng)屬性的結(jié)束值。byValue-> 在不設(shè)置toValue時(shí),toValue = fromValue + byValue,也就是在當(dāng)前的位置上增加多少。affineTransform:該屬性值指定一個(gè)(- (CGAffineTransform)affineTransform;)CGAffineTransform對(duì)象(變換矩陣),該對(duì)象代表CALayer執(zhí)行X,Y兩個(gè)維度(也就是平面)上的旋轉(zhuǎn),縮放,位移,斜切,鏡像等變換矩陣。transform: 該屬性值指定一個(gè)CATransform3D對(duì)象,該對(duì)象代表對(duì)CALayer執(zhí)行X,Y,Z三個(gè)維度(三維空間)中的旋轉(zhuǎn),縮放,位移,斜切,鏡像等變換矩陣。很明顯如果只是對(duì)CALayer進(jìn)行平面上的變換,指定普通的affineTransform屬性即可,如果要對(duì)CALayer執(zhí)行三維空間的變化,則需要指定transform屬性。
CATransform3D:就是下面的結(jié)構(gòu)體
struct CATransform3D
{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
};
其中(m11, m12, m13,m21, m22, m23,m31, m32, m33)將會(huì)組成變換矩陣,m14,m24,m34,m44只是占位符,通常m14,m24,m34會(huì)設(shè)置為0.m14設(shè)置為1.假如變換前的店坐標(biāo)為(x,y,z),與該矩陣相乘后得到變換后該點(diǎn)的坐標(biāo)。按矩陣相乘算法:
[x,y,z].(m11,m12,m13
m21,m22,m23
m31,m32,m33)=(xm11+ym21+zm31 xm12+ym22+zm32 xm13+ym23+z*m33)
上面公司計(jì)算出來的坐標(biāo)還要加上tx,ty,tz這3個(gè)X,Y,Z方向的偏移量。因此對(duì)于點(diǎn)(x,y,z)經(jīng)過CATransform3D變換后,該點(diǎn)的實(shí)際坐標(biāo)為(xm11+ym21+zm31+tx xm12+ym22+zm32+ty xm13+ym23+z*m33+tz).
一般來說可以使用 Core Animation提供的如下函數(shù)來創(chuàng)建三維變換矩陣。
CATransform3DIsIdentity(CATransform3D t) :判斷t矩陣是否為單位矩陣
CATransform3DEqualToTransform(CATransform3D a, CATransform3D b) :判斷兩個(gè)變換矩陣是否相等
CATransform3DMakeTranslation(CGFloat tx, CGFloat ty, CGFloat tz):創(chuàng)建在x方向上移動(dòng)tx,在y方向上移動(dòng)ty,在z方向上移動(dòng)tz的變換矩陣。
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz):創(chuàng)建在x方向上縮放tx,在y方向上縮放ty,在z方向上縮放tz的變換矩陣。
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z) :創(chuàng)建基于指定旋轉(zhuǎn)軸旋轉(zhuǎn)angle弧度的變換,其中x,y,z用于確定旋轉(zhuǎn)軸的方向。比如 (1,0,0)指定旋轉(zhuǎn)軸為x軸,(1,1,0)指定以x,y軸夾角的中線為旋轉(zhuǎn)軸。
CATransform3DTranslate(CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz):以已有t變換矩陣為基礎(chǔ)進(jìn)行位移變換。
CATransform3DScale(CATransform3D t, CGFloat sx, CGFloat sy, CGFloat sz) : 以已有t變換矩陣為基礎(chǔ)進(jìn)行縮放變換。
CATransform3DRotate(CATransform3D t, CGFloat angle, CGFloat x, CGFloat y, CGFloat z):以已有t變換矩陣為基礎(chǔ)進(jìn)行旋轉(zhuǎn)變換。
CATransform3DConcat(CATransform3D a, CATransform3D b):對(duì)a變換矩陣進(jìn)行累加
CATransform3DInvert(CATransform3D t):對(duì)已有的t變換矩陣執(zhí)行反轉(zhuǎn)。
CATransform3DMakeAffineTransform(CGAffineTransform m):將CGAffineTransform矩陣包裝成為CATransform3D變換矩陣,該CATransform3D也只有x,y維度變換。
CATransform3DIsAffine(CATransform3D t) :如果t變換矩陣只有一個(gè)CGAffineTransform矩陣,則改函數(shù)返回YES.
CATransform3DGetAffineTransform(CATransform3D t) :獲取t變換矩陣所包含的CGAffineTransform變換矩陣。
CAPropertyAnimation使用
1:利用+ (instancetype)animationWithKeyPath:(NSString *)keyPath類方法創(chuàng)建屬性動(dòng)畫
2:如果使用基本屬性動(dòng)畫CABasicAnimation,則可指定fromValue,toValue兩個(gè)屬性值,其中fromValue指定動(dòng)畫屬性開始時(shí)的屬性值,toValue指定動(dòng)畫屬性結(jié)束的屬性值.如果使用CAKeyframeAnimation屬性動(dòng)畫,則指定values屬性值,該屬性值是一個(gè) NSArray屬性,其中第一個(gè)元素是屬性的開始值.依次變化.區(qū)別在于CABasicAnimation只能夠指定開始值和結(jié)束值.而CAKeyframeAnimation則可以指定動(dòng)畫屬性的多個(gè)值.CAKeyframeAnimation還可以通過控制路勁來控制移動(dòng).
3:調(diào)用CALayer的- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key添加動(dòng)畫即可.key用于多圖層進(jìn)行分辨.單圖層看不用設(shè)置.
舉例:demo 實(shí)現(xiàn)基本的位移 縮放 旋轉(zhuǎn) 組合動(dòng)畫
#import <QuartzCore/QuartzCore.h>
#import "FKViewController.h"
@implementation FKViewController
CALayer *imageLayer;
- (void)viewDidLoad
{
[superviewDidLoad];
// 創(chuàng)建一個(gè)CALayer對(duì)象
imageLayer = [CALayerlayer];
//設(shè)置該CALayer的邊框、大小、位置等屬性
imageLayer.cornerRadius =6;
imageLayer.borderWidth =1;
imageLayer.borderColor = [UIColorblackColor].CGColor;
imageLayer.masksToBounds =YES;
imageLayer.frame =CGRectMake(30,30, 100, 135);
// 設(shè)置該imageLayer顯示的圖片
imageLayer.contents = (id)[[UIImageimageNamed:@"android"]CGImage];
[self.view.layeraddSublayer:imageLayer];
NSArray* bnTitleArray = [NSArrayarrayWithObjects:@"位移"
, @"旋轉(zhuǎn)" ,@"縮放" ,@"動(dòng)畫組" ,nil];
//獲取屏幕的內(nèi)部高度
CGFloat totalHeight = [UIScreenmainScreen].bounds.size.height;
NSMutableArray* bnArray = [[NSMutableArrayalloc] init];
//采用循環(huán)創(chuàng)建4個(gè)按鈕
for(int i =0 ; i < 4 ; I++)
{
UIButton* bn = [UIButtonbuttonWithType:UIButtonTypeRoundedRect];
bn.frame =CGRectMake(5 + i *80, totalHeight - 45 - 20 , 70 ,35);
[bnsetTitle:[bnTitleArray objectAtIndex:i]
forState:UIControlStateNormal];
[bnArrayaddObject:bn];
[self.viewaddSubview:bn];
}
//為4個(gè)按鈕綁定不同的事件處理方法
[[bnArray objectAtIndex:0]addTarget:selfaction:@selector(move:)
forControlEvents:UIControlEventTouchUpInside];
[[bnArray objectAtIndex:1]addTarget:selfaction:@selector(rotate:)
forControlEvents:UIControlEventTouchUpInside];
[[bnArray objectAtIndex:2]addTarget:selfaction:@selector(scale:)
forControlEvents:UIControlEventTouchUpInside];
[[bnArray objectAtIndex:3]addTarget:selfaction:@selector(group:)
forControlEvents:UIControlEventTouchUpInside];
}
-(void) move:(id)sender
{
CGPoint fromPoint =imageLayer.position;
CGPoint toPoint =CGPointMake(fromPoint.x +80 , fromPoint.y);
// 創(chuàng)建不斷改變CALayer的position屬性的屬性動(dòng)畫
CABasicAnimation* anim = [CABasicAnimation
animationWithKeyPath:@"position"];
//設(shè)置動(dòng)畫開始的屬性值
anim.fromValue = [NSValuevalueWithCGPoint:fromPoint];
//設(shè)置動(dòng)畫結(jié)束的屬性值
anim.toValue = [NSValuevalueWithCGPoint:toPoint];
anim.duration =0.5;
imageLayer.position = toPoint;//設(shè)置移動(dòng)后圖片的位置。
anim.removedOnCompletion =YES;
// 為imageLayer添加動(dòng)畫
[imageLayeraddAnimation:anim forKey:nil];
}
-(void) rotate:(id)sender
{
// 創(chuàng)建不斷改變CALayer的transform屬性的屬性動(dòng)畫
CABasicAnimation* anim = [CABasicAnimationanimationWithKeyPath:@"transform"];
CATransform3D fromValue =imageLayer.transform;
//設(shè)置動(dòng)畫開始的屬性值
anim.fromValue = [NSValuevalueWithCATransform3D:fromValue];
// 繞X軸旋轉(zhuǎn)180度
CATransform3D toValue =CATransform3DRotate(fromValue, M_PI , 1 , 0 , 0);
// 繞Y軸旋轉(zhuǎn)180度
// CATransform3D toValue = CATransform3DRotate(fromValue, M_PI , 0 , 1 , 0);
// // 繞Z軸旋轉(zhuǎn)180度
// CATransform3D toValue = CATransform3DRotate(fromValue, M_PI , 0 , 0 , 1);
//設(shè)置動(dòng)畫結(jié)束的屬性值
anim.toValue = [NSValuevalueWithCATransform3D:toValue];
anim.duration =0.5;
imageLayer.transform = toValue;
anim.removedOnCompletion =YES;
// 為imageLayer添加動(dòng)畫
[imageLayeraddAnimation:anim forKey:nil];
}
-(void) scale:(id)sender
{
// 創(chuàng)建不斷改變CALayer的transform屬性的屬性動(dòng)畫
CAKeyframeAnimation* anim = [CAKeyframeAnimation
animationWithKeyPath:@"transform"];
// 設(shè)置CAKeyframeAnimation控制transform屬性依次經(jīng)過的屬性值
anim.values = [NSArrayarrayWithObjects:
[NSValuevalueWithCATransform3D:imageLayer.transform],
[NSValuevalueWithCATransform3D:CATransform3DScale
(imageLayer.transform ,0.2, 0.2, 1)],
[NSValuevalueWithCATransform3D:CATransform3DScale
(imageLayer.transform,2, 2 , 1)],
[NSValuevalueWithCATransform3D:imageLayer.transform],nil];
anim.duration =5;
anim.removedOnCompletion =YES;
// 為imageLayer添加動(dòng)畫
[imageLayeraddAnimation:anim forKey:nil];
}
-(void) group:(id)sender
{
CGPoint fromPoint =imageLayer.position;
CGPoint toPoint =CGPointMake(280 , fromPoint.y +300);
// 創(chuàng)建不斷改變CALayer的position屬性的屬性動(dòng)畫
CABasicAnimation* moveAnim = [CABasicAnimation
animationWithKeyPath:@"position"];
//設(shè)置動(dòng)畫開始的屬性值
moveAnim.fromValue = [NSValuevalueWithCGPoint:fromPoint];
//設(shè)置動(dòng)畫結(jié)束的屬性值
moveAnim.toValue = [NSValuevalueWithCGPoint:toPoint];
moveAnim.removedOnCompletion =YES;
// 創(chuàng)建不斷改變CALayer的transform屬性的屬性動(dòng)畫
CABasicAnimation* transformAnim = [CABasicAnimation
animationWithKeyPath:@"transform"];
CATransform3D fromValue =imageLayer.transform;
//設(shè)置動(dòng)畫開始的屬性值
transformAnim.fromValue = [NSValuevalueWithCATransform3D: fromValue];
//創(chuàng)建縮放為X、Y兩個(gè)方向上縮放為0.5的變換矩陣
CATransform3D scaleValue =CATransform3DScale(fromValue , 0.5 , 0.5, 1);
//繞Z軸旋轉(zhuǎn)180度的變換矩陣
CATransform3D rotateValue =CATransform3DRotate(fromValue, M_PI , 0 , 0 , 1);
//計(jì)算兩個(gè)變換矩陣的和
CATransform3D toValue =CATransform3DConcat(scaleValue, rotateValue);
//設(shè)置動(dòng)畫技術(shù)的屬性值
transformAnim.toValue = [NSValuevalueWithCATransform3D:toValue];
//動(dòng)畫效果累加
transformAnim.cumulative =YES;
//動(dòng)畫重復(fù)執(zhí)行2次,旋轉(zhuǎn)360度
transformAnim.repeatCount =2;
transformAnim.duration =3;
//位移、縮放、旋轉(zhuǎn)組合起來執(zhí)行
CAAnimationGroup *animGroup = [CAAnimationGroupanimation];
animGroup.animations = [NSArrayarrayWithObjects:moveAnim
, transformAnim ,nil];
animGroup.duration =6;
// 為imageLayer添加動(dòng)畫
[imageLayeraddAnimation:animGroup forKey:nil];
}
@end
舉例:控制移動(dòng)的路徑
對(duì)于CAKeyframeAnimation而言,它除了可通過values屬性指定動(dòng)畫過程中的多個(gè)值之外,還可以通過path屬性指定CALayer的移動(dòng)路徑,改屬性就是CGPathRef,通過這種方式即可控制CALayer按我們指定的軌跡移動(dòng),從而執(zhí)行更加細(xì)致的動(dòng)畫。
#import <QuartzCore/QuartzCore.h>
#import "FKViewController.h"
@interface FKViewController ()
@end
@implementation FKViewController
CALayer* fishLayer;
NSInteger fishFrame;
NSTimer* timer;
// 定義NSMutableArray裝魚的10個(gè)動(dòng)畫幀
NSMutableArray* fishFrameArray;
- (void)viewDidLoad
{
[superviewDidLoad];
// 創(chuàng)建CALayer作為背景
CALayer* bg = [CALayerlayer];
//設(shè)置背景圖片
bg.contents = (id)[UIImageimageNamed:@"bg.jpg"].CGImage;
bg.contentsGravity =kCAGravityCenter;
bg.frame =CGRectMake(0,0, 320, 480);
[self.view.layeraddSublayer:bg];
fishFrameArray = [[NSMutableArrayalloc] init];
// 初始化魚的10個(gè)動(dòng)畫幀,并添加到fishFrameArray集合中
for(int i =0 ; i < 10 ; I++)
{
[fishFrameArrayaddObject:[UIImageimageNamed:
[NSStringstringWithFormat:@"fish%d.png" , i]]];//多張連串的圖片
}
//創(chuàng)建定時(shí)器控制小魚的動(dòng)畫幀的改變。
timer = [NSTimerscheduledTimerWithTimeInterval:0.15target:self
selector:@selector(change)userInfo:nilrepeats:YES];
// 創(chuàng)建CALayer
fishLayer = [CALayerlayer];
//設(shè)置CALayer顯示內(nèi)容的對(duì)齊、縮放模式(不縮放,直接顯示在中間)
fishLayer.contentsGravity =kCAGravityCenter;
// 設(shè)置fishLayer的大小
fishLayer.frame =CGRectMake(128,6, 90, 40);
[self.view.layeraddSublayer:fishLayer];
//創(chuàng)建一個(gè)按鈕,通過該按鈕觸發(fā)小魚的游動(dòng)
UIButton* bn = [UIButtonbuttonWithType:UIButtonTypeRoundedRect];
bn.frame =CGRectMake(10 ,10 , 60 , 35);
[bn setTitle:@"開始"forState:UIControlStateNormal];
[self.viewaddSubview:bn];
//用戶點(diǎn)擊按鈕時(shí),激發(fā)start:方法
[bnaddTarget:selfaction:@selector(start:)
forControlEvents:UIControlEventTouchUpInside];
}
-(void) start:(id)sender
{
// 創(chuàng)建對(duì)CALayer的position屬性執(zhí)行控制的屬性動(dòng)畫
CAKeyframeAnimation* anim = [CAKeyframeAnimation
animationWithKeyPath:@"position"];
// 創(chuàng)建路徑
CGMutablePathRef movePath =CGPathCreateMutable();
//添加一條圓形的路徑
CGPathAddArc(movePath,nil, 170, 175, 150, -M_PI /2, M_PI * 3 / 2, YES);
//設(shè)置anim動(dòng)畫的移動(dòng)路徑
anim.path = movePath;
// 創(chuàng)建對(duì)CALayer的transform屬性執(zhí)行控制的屬性動(dòng)畫
CAKeyframeAnimation* anim2 = [CAKeyframeAnimation
animationWithKeyPath:@"transform"];
//指定關(guān)鍵幀動(dòng)畫的3個(gè)關(guān)鍵值:分別是不旋轉(zhuǎn),旋轉(zhuǎn)180度,旋轉(zhuǎn)360度
anim2.values = [NSArrayarrayWithObjects:
[NSValuevalueWithCATransform3D:CATransform3DIdentity],
[NSValuevalueWithCATransform3D:
CATransform3DMakeRotation(M_PI , 0, 0,1)],
[NSValuevalueWithCATransform3D:
CATransform3DMakeRotation(2 * M_PI , 0,0, 1)]
,nil];
//使用動(dòng)畫組來組合2個(gè)動(dòng)畫
CAAnimationGroup *animGroup = [CAAnimationGroupanimation];
animGroup.animations = [NSArrayarrayWithObjects:anim, anim2, nil];
//指定動(dòng)畫重復(fù)10次
animGroup.repeatCount =10;
animGroup.duration =24;
// 為fishLayer添加動(dòng)畫
[fishLayeraddAnimation:animGroup forKey:@"move"];
}
// 該方法由定時(shí)器觸發(fā),不斷更改fishLayer顯示的動(dòng)畫幀
- (void) change
{
fishLayer.contents = (id)[[fishFrameArray
objectAtIndex:fishFrame++ %10] CGImage];
}
@end
4:CAAnimationGroup 動(dòng)畫組,方便對(duì)于多動(dòng)畫的統(tǒng)一控制管理。
能將多個(gè)動(dòng)畫組合在一起,如平移、縮放、旋轉(zhuǎn)等效果組合在一起做出更炫酷的的效果。它只有一個(gè)特有的屬性。
animations-> 所有動(dòng)畫效果元素的數(shù)組。
舉例1:
@property(nullable, copy) NSArray<CAAnimation *> *animations;
NSLog(@"動(dòng)畫執(zhí)行前redView.frame:%@", NSStringFromCGRect(self.redView.frame));
//平移
CABasicAnimation *transition = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
transition.toValue = @(300);
//旋轉(zhuǎn)
CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotation.toValue = @(M_PI);
//縮放
CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scale.toValue = @(0.2);
//添加組動(dòng)畫
CAAnimationGroup *group = [CAAnimationGroup animation];
//注意這里動(dòng)畫的效果 要設(shè)置成group的
group.duration = 2.0;
group.animations = @[rotation, scale, transition];
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
[self.redView.layer addAnimation:group forKey:nil];
image.gif
舉例2:
@interface TestAnimationGroupVC ()
@property (nonatomic,strong) UIView *colorView;
@property (nonatomic,strong) UIBezierPath *bezierPath;
@end
@implementation TestAnimationGroupVC
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建顯示顏色的圖層
self.colorView = [UIView new];
self.colorView.frame = CGRectMake(0, 0, 60, 60);
self.colorView.center = CGPointMake(50, 200);
self.colorView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:self.colorView];
//創(chuàng)建貝塞爾曲線,即幀動(dòng)畫運(yùn)動(dòng)軌跡
self.bezierPath = [[UIBezierPath alloc] init];
[self.bezierPath moveToPoint:CGPointMake(50, 200)];
[self.bezierPath addCurveToPoint:CGPointMake(kDeviceWidth - 50, 200) controlPoint1:CGPointMake(150, 50) controlPoint2:CGPointMake(kDeviceWidth - 150, 250)];
//繪制繪制path,便于觀察動(dòng)畫;
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.path = self.bezierPath.CGPath;
pathLayer.fillColor = [UIColor clearColor].CGColor;
pathLayer.strokeColor = [UIColor redColor].CGColor;
pathLayer.lineWidth = 3.0f;
[self.view.layer addSublayer:pathLayer];
}
- (IBAction)startAnimation:(UIButton *)sender{
//移除可能未執(zhí)行完的動(dòng)畫,防止多重動(dòng)畫導(dǎo)致異常
[self.colorView.layer removeAnimationForKey:@"groupAnimation"];
//1.創(chuàng)建基礎(chǔ)動(dòng)畫:修改背景色為紫色
CABasicAnimation *basicAnimation = [CABasicAnimation animation];
basicAnimation.keyPath = @"backgroundColor";
basicAnimation.toValue = (__bridge id _Nullable)([UIColor purpleColor].CGColor);
//2.創(chuàng)建關(guān)鍵幀動(dòng)畫
CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animation];
keyFrameAnimation.keyPath = @"position";
keyFrameAnimation.path = self.bezierPath.CGPath;
keyFrameAnimation.rotationMode = kCAAnimationRotateAuto;
//3.創(chuàng)建組動(dòng)畫:組合基礎(chǔ)動(dòng)畫和關(guān)鍵幀動(dòng)畫
CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
groupAnimation.animations = @[basicAnimation, keyFrameAnimation];
groupAnimation.duration = 4.0;
[self.colorView.layer addAnimation:groupAnimation forKey:@"groupAnimation"];
}
動(dòng)畫組的效果如下:

5:CABasicAnimation基礎(chǔ)動(dòng)畫
CABasicAnimation即基礎(chǔ)動(dòng)畫,在指定可動(dòng)畫屬性后,動(dòng)畫會(huì)按照預(yù)定的參數(shù)持續(xù)一定時(shí)間由初始值變換為終點(diǎn)值。其實(shí),CABasicAnimation就相當(dāng)于只有開始和結(jié)束兩個(gè)幀的特殊關(guān)鍵幀動(dòng)畫(后續(xù)會(huì)詳解);
屬性 屬性說明
fromValue-> 起始值toValue-> 結(jié)束值byValue-> keyPath屬性的變化值
下面的示例使用CABasicAnimation實(shí)現(xiàn)了修改顏色圖層colorLayer的背景色為隨機(jī)顏色的動(dòng)畫,具體的代碼如下:
@interface TestBacicAnimation1VC ()<CAAnimationDelegate>
@property (nonatomic,strong) CALayer *colorLayer;
@end
@implementation TestBacicAnimation1VC
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建顯示顏色的圖層,添加于視圖控制器的View上
CALayer *colorLayer = [CALayer layer];
colorLayer.frame = CGRectMake(50, 50, 100, 100);
colorLayer.backgroundColor = [UIColor redColor].CGColor;
self.colorLayer = colorLayer;
[self.view.layer addSublayer:colorLayer];
}
- (IBAction)changeColor:(UIButton *)sender{
//步驟1:創(chuàng)建動(dòng)畫
CABasicAnimation *animation = [CABasicAnimation animation];
animation.keyPath = @"backgroundColor";
//步驟2:設(shè)定動(dòng)畫屬性
animation.autoreverses = NO;
animation.duration = 0.25;
animation.repeatCount = 1;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.delegate = self;
UIColor *randomColor = [UIColor randomColor]; //自定義獲取隨機(jī)色的方法
animation.toValue = (__bridge id _Nullable)(randomColor.CGColor);
//步驟3:添加動(dòng)畫到圖層
[self.colorLayer addAnimation:animation forKey:@"keyPath_backgroundColor"];
}
- (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag{
//禁用隱式動(dòng)畫
[CATransaction begin];
[CATransaction setDisableActions:true];
self.colorLayer.backgroundColor = (__bridge CGColorRef)anim.toValue;
[CATransaction commit];
}
效果如下:
image.gif
總結(jié)創(chuàng)建動(dòng)畫的兩種方式如下:
//方法1:實(shí)例化同時(shí)指定動(dòng)畫類型
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
//方法2:先實(shí)例化,再指定動(dòng)畫類型
CABasicAnimation *animation = [CABasicAnimation animation];
animation.keyPath = @"backgroundColor";
關(guān)閉隱式動(dòng)畫
對(duì)獨(dú)立圖層(即非UIView的關(guān)聯(lián)圖層,類似上述例子中的colorLayer)做更新屬性的顯式動(dòng)畫,我們需要設(shè)置一個(gè)事務(wù)來禁用圖層行為,否則動(dòng)畫會(huì)發(fā)生兩次,一次是因?yàn)轱@式的CABasicAnimation,另一次是因?yàn)殡[式動(dòng)畫,從而導(dǎo)致我們看到的動(dòng)畫異常。
6:CAKeyframeAnimation 關(guān)鍵幀動(dòng)畫
CAKeyframeAnimation 關(guān)鍵幀動(dòng)畫,同樣通過·keyPath·對(duì)應(yīng)屬性進(jìn)行控制,但它可以通過·values·或者·path·進(jìn)行多個(gè)階段的控制,屬性如下:
values-> 關(guān)鍵幀組成的數(shù)組,動(dòng)畫會(huì)依次顯示其中的每一幀。path-> 關(guān)鍵幀路徑,動(dòng)畫進(jìn)行的要素,優(yōu)先級(jí)比values高,但是只對(duì)CALayer的anchorPoint和position起作用。如果你設(shè)置了path,那么values將被忽略keyTimes-> 每一幀對(duì)應(yīng)的時(shí)間,如果不設(shè)置,則各關(guān)鍵幀平分設(shè)定時(shí)間。timingFunctions-> 每一幀對(duì)應(yīng)的動(dòng)畫節(jié)奏。calculationMode-> 動(dòng)畫的計(jì)算模式,系統(tǒng)提供了對(duì)應(yīng)的幾種模式。tensionValues-> 動(dòng)畫張力控制。continuityValues-> 動(dòng)畫連續(xù)性控制。biasValues-> 動(dòng)畫偏差率控制。rotationMode-> 動(dòng)畫沿路徑旋轉(zhuǎn)方式,系統(tǒng)提供了兩種模式。
簡(jiǎn)單的創(chuàng)建一個(gè)帶路徑的動(dòng)畫效果,比較粗糙,不過事先原理都是一樣的
代碼如下:
實(shí)現(xiàn)幀動(dòng)畫:使用values
從關(guān)鍵幀動(dòng)畫的屬性可以看出,我們可以總結(jié)出關(guān)鍵幀動(dòng)畫的實(shí)現(xiàn)方式實(shí)際分為兩種:
1.通過values設(shè)置關(guān)鍵幀屬性值數(shù)組;
2.通過path設(shè)置關(guān)鍵幀路徑,而且此種方式的優(yōu)先級(jí)較高;
這里首先測(cè)試第一種方式,實(shí)現(xiàn)這樣的關(guān)鍵幀動(dòng)畫:創(chuàng)建一個(gè)紫色滑塊在四個(gè)坐標(biāo)點(diǎn)之間滑動(dòng);具體的代碼實(shí)現(xiàn)如下:
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建測(cè)試幀動(dòng)畫的紫色圖層
UIView *purpleView = [UIView new];
purpleView.frame = CGRectMake(0, 0, 50, 50);
purpleView.center = CGPointMake(50, 100);
purpleView.backgroundColor = [UIColor purpleColor];
[self.view addSubview:purpleView];
//步驟1:創(chuàng)建動(dòng)畫
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"position";
//步驟2:設(shè)置動(dòng)畫關(guān)鍵幀數(shù)據(jù)
NSValue *value1 = [NSValue valueWithCGPoint:CGPointMake(50, 100)];
NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(kDeviceWidth -50, 100)];
NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(kDeviceWidth -50, kDeviceWidth- 100)];
NSValue *value4 = [NSValue valueWithCGPoint:CGPointMake(50, kDeviceWidth -100)];
NSValue *value5 = [NSValue valueWithCGPoint:CGPointMake(50, 100)];
animation.values = @[value1,value2,value3,value4,value5];
//步驟3:設(shè)定動(dòng)畫屬性
animation.repeatCount = MAXFLOAT; //重復(fù)執(zhí)行
animation.autoreverses = NO;
animation.removedOnCompletion = NO;
animation.duration = 4;
//animation.keyTimes = @[@(0), @(1 / 10.0), @(5 / 10.0), @(9 / 10.0), @(1) ];
animation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[purpleView.layer addAnimation:animation forKey:nil];
}
關(guān)鍵幀動(dòng)畫效果如下:

實(shí)現(xiàn)關(guān)鍵幀動(dòng)畫:使用path
現(xiàn)在,我們測(cè)試CAKeyframeAnimation使用path實(shí)現(xiàn)這樣一個(gè)動(dòng)畫:一架飛機(jī)沿著一個(gè)簡(jiǎn)單的曲線運(yùn)動(dòng)飛行;具體的操作包括以下幾個(gè)步驟:
1.使用UIKit提供的UIBezierPath類創(chuàng)建貝塞爾曲線,作為飛機(jī)飛行的路線軌跡;
2.使用CAShapeLayer在屏幕上繪制曲線(此步驟對(duì)于動(dòng)畫不是必須的,只是為了動(dòng)畫看起來更直觀);
3.創(chuàng)建用于顯示飛機(jī)的視圖,將其設(shè)置在貝塞爾曲線的初始位置;
4.創(chuàng)建并執(zhí)行關(guān)鍵幀動(dòng)畫,實(shí)現(xiàn)飛機(jī)飛行的曲線動(dòng)畫;
- (void)viewDidLoad {
[super viewDidLoad];
//1.創(chuàng)建三次貝塞爾曲線(一種使用起始點(diǎn),結(jié)束點(diǎn)和另外兩個(gè)控制點(diǎn)定義的曲線);
UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
[bezierPath moveToPoint:CGPointMake(50, 200)];
[bezierPath addCurveToPoint:CGPointMake(kDeviceWidth - 50, 200) controlPoint1:CGPointMake(150, 50) controlPoint2:CGPointMake(kDeviceWidth - 150, 250)];
//2.繪制飛行路線
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.path = bezierPath.CGPath;
pathLayer.fillColor = [UIColor clearColor].CGColor;
pathLayer.strokeColor = [UIColor redColor].CGColor;
pathLayer.lineWidth = 3.0f;
[self.view.layer addSublayer:pathLayer];
//3.創(chuàng)建顯示飛機(jī)的視圖
UIImageView *airPlaneImgView = [[UIImageView alloc] init];
airPlaneImgView.frame = CGRectMake(0, 0, 50, 50);
airPlaneImgView.center = CGPointMake(50, 200);
airPlaneImgView.image = [UIImage imageNamed:@"airplane"];
[self.view addSubview:airPlaneImgView];
//4.設(shè)置關(guān)鍵幀動(dòng)畫
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"position";
animation.duration = 5.0;
animation.path = bezierPath.CGPath;
animation.rotationMode = kCAAnimationRotateAuto; //設(shè)置根據(jù)曲線的切線自動(dòng)旋轉(zhuǎn),讓動(dòng)畫更加真實(shí)
[airPlaneImgView.layer addAnimation:animation forKey:nil];
}
關(guān)鍵幀動(dòng)畫效果圖如下:

7:CATransition 轉(zhuǎn)場(chǎng)動(dòng)畫,系統(tǒng)提供了很多酷炫效果。屬性如下:
type-> 轉(zhuǎn)場(chǎng)動(dòng)畫類型。
kCATransitionFade:交叉淡化過渡
kCATransitionPush:新視圖吧舊視圖
kCATransitionMoveIn:新視圖移到舊視圖上面
kCATransitionReveal:將舊視圖移開,顯示下面的視圖
用字符串表示:
pageCurl:向上翻頁效果
pageUnCurl:向下翻頁效果
cube:立方體翻滾效果
oglFlip:上下左右翻轉(zhuǎn)效果
rippleEffect:波紋
suckEffect:吮吸
flipFromLeft:左翻轉(zhuǎn)
flipFromRight:右翻轉(zhuǎn)
suckEffect:收縮效果,如一塊布被抽走
rippleEffect:水滴效果
cameraIrisHollowOpen:相機(jī)鏡頭打開效果
cameraIrisHollowClose:相機(jī)鏡頭關(guān)閉效果subtype-> 轉(zhuǎn)場(chǎng)動(dòng)畫方向。
kCATransitionFromRight 從右向左,kCATransitionFromTop 從上向下,kCATransitionFromLeft 從左向右,kCATransitionFromBottom 從下向上startProgress-> 動(dòng)畫起點(diǎn)進(jìn)度(整體的百分比)。endProgress-> 動(dòng)畫終點(diǎn)進(jìn)度(整體的百分比)。filter-> 自定義轉(zhuǎn)場(chǎng)。duration:動(dòng)畫執(zhí)行時(shí)間timingFunction: 動(dòng)畫的運(yùn)動(dòng)軌跡,用于變化起點(diǎn)和終點(diǎn)之間的插值計(jì)算,形象點(diǎn)說它決定了動(dòng)畫運(yùn)行的節(jié)奏,比如是均勻變化(相同時(shí)間變化量相同)還是先快后慢,先慢后快還是先慢再快再慢
kCAMediaTimingFunctionLinear 線性,即勻速
kCAMediaTimingFunctionEaseIn 先慢后快
kCAMediaTimingFunctionEaseOut 先快后慢
kCAMediaTimingFunctionEaseInEaseOut 先慢后快再慢
kCAMediaTimingFunctionDefault 實(shí)際效果是動(dòng)畫中間比較快
示例1:
//轉(zhuǎn)場(chǎng)動(dòng)畫
-(void)transitionAnimation{
CATransition *transtion = [CATransition animation];
transtion.type = @"rippleEffect";
transtion.subtype = kCATransitionFromLeft;//kCATransitionFromLeft kCATransitionFromRight
transtion.duration = 1;
_transtionIndex++;
if (_transtionIndex > 4) {
_transtionIndex = 1;
}
_aniLayer.contents = (id)[UIImage imageNamed:[NSString stringWithFormat:@"%@.jpg",@(_transtionIndex)]].CGImage;
[_aniLayer addAnimation:transtion forKey:@"transtion"];
}
示例2:
//創(chuàng)建動(dòng)畫
CATransition *transition = [[CATransition alloc]init];
transition.duration = 0.5;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
transition.type = kCATransitionReveal;
transition.subtype = kCATransitionFromBottom;
UULoginUserViewController *login = [[UULoginUserViewController alloc] init];
UUNavigationController *nav = [[UUNavigationController alloc] initWithRootViewController:login];
self.window.rootViewController = nav;
[self.window.layer addAnimation:transition forKey:@"animation"];
示例3:
@interface TestTransition1VC ()
@property (nonatomic,strong) UIImageView *imageView;
@property (nonatomic,strong) NSArray *images;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *subtype;
@end
@implementation TestTransition1VC
- (void)viewDidLoad {
[super viewDidLoad];
self.images = @[[UIImage imageNamed:@"tree_spring"],
[UIImage imageNamed:@"tree_summer"],
[UIImage imageNamed:@"tree_autumn"],
[UIImage imageNamed:@"tree_winter"]];
self.type = kCATransitionFade;
self.subtype = kCATransitionFromRight;
}
- (void)perforomTransitionAnimation{
CATransition *transition = [[CATransition alloc] init];
transition.type = _type;
transition.subtype = _subtype;
transition.duration = 0.5;
[self.imageView.layer addAnimation:transition forKey:nil];
UIImage *currentImage = self.imageView.image;
NSUInteger index = [self.images indexOfObject:currentImage];
index = (index + 1) % self.images.count;
self.imageView.image = self.images[index];
}
過渡動(dòng)畫的效果如下:

自定義過渡動(dòng)畫
過渡動(dòng)畫的過程就是對(duì)原始圖層外觀截圖,然后添加一段動(dòng)畫,平滑過渡到圖層改變之后的那個(gè)截圖效果。如果我們知道如何對(duì)圖層截圖,我們就可以使用屬性動(dòng)畫來自定義CATransition動(dòng)畫了。
CALayer有一個(gè)-renderInContenxt:方法,通過它可以將圖層繪制到Core Graphics的上下文中捕獲當(dāng)前內(nèi)容的圖片;所以現(xiàn)在我們嘗試這樣的實(shí)現(xiàn):對(duì)當(dāng)前視圖控制器View進(jìn)行截圖,然后在改變其背景色的時(shí)候?qū)貓D快速旋轉(zhuǎn)并且淡出,以達(dá)到一種過渡的效果;具體的代碼示例如下:
- (void)performAnimation{
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, YES, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *coverImage = UIGraphicsGetImageFromCurrentImageContext();
UIView *coverView = [[UIImageView alloc] initWithImage:coverImage];
coverView.frame = self.view.bounds;
[self.view addSubview:coverView];
//使用自定義方法得到隨機(jī)顏色(切換后的顏色)
UIColor *randomColor = [UIColor randomColor];
self.view.backgroundColor = randomColor;
//使用UIView動(dòng)畫方法來代替屬性動(dòng)畫(為了簡(jiǎn)化代碼步驟)
[UIView animateWithDuration:1 animations:^{
CGAffineTransform transform = CGAffineTransformMakeScale(0.01, 0.01);
transform = CGAffineTransformRotate(transform, M_PI_2);
coverView.transform = transform;
coverView.alpha = 0.0;
} completion:^(BOOL finished) {
[coverView removeFromSuperview];
}];
}
自定義過渡動(dòng)畫的效果如下:

7:CASpringAnimation彈簧動(dòng)畫
CASpringAnimation彈簧動(dòng)畫,帶有初始速度以及阻尼指數(shù)等物理參數(shù)的屬性動(dòng)畫。我們可以把它看成在不絕對(duì)光滑的地面上,一個(gè)彈簧拴著別小球,那么我們可以這么理解他的屬性(物理知識(shí)請(qǐng)問一下牛頓大叔):
mass-> 質(zhì)量越大,彈簧拉伸和壓縮的幅度越大,動(dòng)畫的速度變慢,并且波動(dòng)幅度變大,影響圖層運(yùn)動(dòng)時(shí)的彈簧慣性stiffness-> 彈簧的勁度系數(shù)。剛度系數(shù)越大,形變產(chǎn)生的力就越大,運(yùn)動(dòng)越快damping-> 阻尼系數(shù),地面的摩擦力。阻尼系數(shù)越大,停止越快initialVelocity-> 初始速度,相當(dāng)于給小球一個(gè)初始速度(可正可負(fù),方向不同),初始速率,動(dòng)畫視圖的初始速度大小
速率為正數(shù)時(shí),速度方向與運(yùn)動(dòng)方向一致,速率為負(fù)數(shù)時(shí),速度方向與運(yùn)動(dòng)方向相反settlingDuration-> 結(jié)算時(shí)間 返回彈簧動(dòng)畫到停止時(shí)的估算時(shí)間,根據(jù)當(dāng)前的動(dòng)畫參數(shù)估算 通常彈簧動(dòng)畫的時(shí)間使用結(jié)算時(shí)間比較準(zhǔn)確
示例:
self.animationView = [[UIView alloc]init];
self.animationView.frame = CGRectMake(0, kHeight/2-50, 50, 50);
self.animationView.backgroundColor = [UIColor greenColor];
[self.view addSubview:self.animationView];
//彈簧效果
CASpringAnimation *spring = [CASpringAnimation animationWithKeyPath:@"position.y"];
spring.fromValue = @150;
spring.toValue = @100;
//阻尼系數(shù)
spring.damping = 0.1;
//剛度系數(shù): (勁度系數(shù) / 彈性系數(shù)): 系數(shù)越大,形變的產(chǎn)生的力越大, 運(yùn)動(dòng)越快
spring.stiffness = 10;
//質(zhì)量: 影響圖層運(yùn)動(dòng)時(shí)候的慣性, 質(zhì)量越大彈簧拉伸和壓縮的幅度越大 (動(dòng)畫的幅度,波動(dòng)變大)
spring.mass = 1;
//初識(shí)速率: 動(dòng)畫視圖的初識(shí)速度大小
//速率為正時(shí)候, 速度方向與運(yùn)動(dòng)方向一致, 否則相仿.
spring.initialVelocity = 1;
// settlingDuration 結(jié)算時(shí)間,預(yù)估彈簧動(dòng)畫到停住的時(shí)間的估算, 根據(jù)當(dāng)前動(dòng)畫的各個(gè)參數(shù)估算, 通常彈簧動(dòng)畫的估算時(shí)間使用結(jié)算時(shí)間比較準(zhǔn)確
spring.duration = spring.settlingDuration;
[self.animationView.layer addAnimation:spring forKey:@"springAnimation"];
最后
看完這些相信你對(duì) iOS 中的動(dòng)畫有了一個(gè)詳細(xì)的了解, 其實(shí)單個(gè)動(dòng)畫都是比較簡(jiǎn)單的, 而復(fù)雜的動(dòng)畫其實(shí)都是由一個(gè)個(gè)簡(jiǎn)單的動(dòng)畫組裝而成的,所以遇到比較難得動(dòng)畫需求, 我們只要充分組裝不同的動(dòng)畫,就能實(shí)現(xiàn)出滿意的效果.
好記性不如爛筆頭, 光說不練假把戲, 建議大家結(jié)合我的代碼, 自己邊看邊練習(xí), 這樣才能記得牢, 才能轉(zhuǎn)換成自己的知識(shí).
此處有個(gè)demo,可以去看看別人寫的東西。
github: https://github.com/YTiOSer/YTAnimation

