国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

CALayer及動畫

2019-11-09 18:47:11
字體:
供稿:網(wǎng)友

轉(zhuǎn)自http://www.cnblogs.com/kenshincui/p/3972100.html

1.CALayer

CALayer簡介

在介紹動畫操作之前我們必須先來了解一個動畫中常用的對象CALayer。CALayer包含在QuartzCore框架中,這是一個跨平臺的框架,既可以用在iOS中又可以用在Mac OS X中。在使用Core Animation開發(fā)動畫的本質(zhì)就是將CALayer中的內(nèi)容轉(zhuǎn)化為位圖從而供硬件操作,所以要熟練掌握動畫操作必須先來熟悉CALayer。

在上一篇文章中使用Quartz 2D繪圖時大家其實已經(jīng)用到了CALayer,當(dāng)利用drawRect:方法繪圖的本質(zhì)就是繪制到了UIView的layer(屬性)中,可是這個過程大家在上一節(jié)中根本體會不到。但是在Core Animation中我們操作更多的則不再是UIView而是直接面對CALayer。下圖描繪了CALayer和UIView的關(guān)系,在UIView中有一個layer屬性作為根圖層,根圖層上可以放其他子圖層,在UIView中所有能夠看到的內(nèi)容都包含在layer中:

這里寫圖片描述

CALayer常用屬性

在iOS中CALayer的設(shè)計主要是了為了內(nèi)容展示和動畫操作,CALayer本身并不包含在UIKit中,它不能響應(yīng)事件。由于CALayer在設(shè)計之初就考慮它的動畫操作功能,CALayer很多屬性在修改時都能形成動畫效果,這種屬性稱為“隱式動畫屬性”。但是對于UIView的根圖層而言屬性的修改并不形成動畫效果,因為很多情況下根圖層更多的充當(dāng)容器的做用,如果它的屬性變動形成動畫效果會直接影響子圖層。另外,UIView的根圖層創(chuàng)建工作完全由iOS負(fù)責(zé)完成,無法重新創(chuàng)建,但是可以往根圖層中添加子圖層或移除子圖層。

下表列出了CALayer常用的屬性: 這里寫圖片描述 這里寫圖片描述

隱式屬性動畫的本質(zhì)是這些屬性的變動默認(rèn)隱含CABasicAnimation動畫實現(xiàn),詳情大家可以參照Xcode幫助文檔中“Animatable PRoperties”一節(jié)。在CALayer中很少使用frame屬性,因為frame本身不支持動畫效果,通常使用bounds和position代替。CALayer中透明度使用opacity表示而不是alpha;中心點(diǎn)使用position表示而不是center。anchorPoint屬性是圖層的錨點(diǎn),范圍在(0~1,0~1)表示在x、y軸的比例,這個點(diǎn)永遠(yuǎn)可以同position(中心點(diǎn))重合,當(dāng)圖層中心點(diǎn)固定后,調(diào)整anchorPoint即可達(dá)到調(diào)整圖層顯示位置的作用(因為它永遠(yuǎn)和position重合)為了進(jìn)一步說明anchorPoint的作用,假設(shè)有一個層大小100*100,現(xiàn)在中心點(diǎn)位置(50,50),由此可以得出frame(0,0,100,100)。上面說過anchorPoint默認(rèn)為(0.5,0.5),同中心點(diǎn)position重合,此時使用圖形描述如圖1;當(dāng)修改anchorPoint為(0,0),此時錨點(diǎn)處于圖層左上角,但是中心點(diǎn)poition并不會改變,因此圖層會向右下角移動,如圖2;然后修改anchorPoint為(1,1,),position還是保持位置不變,錨點(diǎn)處于圖層右下角,此時圖層如圖3。

這里寫圖片描述

CALayer繪圖

上一篇文章中重點(diǎn)討論了使用Quartz 2D繪圖,當(dāng)時調(diào)用了UIView的drawRect:方法繪制圖形、圖像,這種方式本質(zhì)還是在圖層中繪制,但是這里會著重介紹一下如何直接在圖層中繪圖。在圖層中繪圖的方式跟原來基本沒有區(qū)別,只是drawRect:方法是由UIKit組件進(jìn)行調(diào)用,因此里面可以使用一些UIKit封裝的方法進(jìn)行繪圖,而直接繪制到圖層的方法由于并非UIKit直接調(diào)用因此只能用原生的Core Graphics方法繪制。

圖層繪圖有兩種方法,不管使用哪種方法繪制完必須調(diào)用圖層的setNeedDisplay方法(注意是圖層的方法,不是UIView的方法,前面我們介紹過UIView也有此方法)

通過圖層代理drawLayer: inContext:方法繪制 通過自定義圖層drawInContext:方法繪制 使用代理方法繪圖

通過代理方法進(jìn)行圖層繪圖只要指定圖層的代理,然后在代理對象中重寫-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx方法即可。需要注意這個方法雖然是代理方法但是不用手動實現(xiàn)CALayerDelegate,因為CALayer定義中給NSObject做了分類擴(kuò)展,所有的NSObject都包含這個方法。另外設(shè)置完代理后必須要調(diào)用圖層的setNeedDisplay方法,否則繪制的內(nèi)容無法顯示。

2.Core Animation

大家都知道在iOS中實現(xiàn)一個動畫相當(dāng)簡單,只要調(diào)用UIView的塊代碼即可實現(xiàn)一個動畫效果,這在其他系統(tǒng)開發(fā)中基本不可能實現(xiàn)。下面通過一個簡單的UIView進(jìn)行一個圖片放大動畫效果演示:

- (void)viewDidLoad { [super viewDidLoad]; UIImage *image=[UIImage imageNamed:@"open2.png"]; UIImageView *imageView=[[UIImageView alloc]init]; imageView.image=image; imageView.frame=CGRectMake(120, 140, 80, 80); [self.view addSubview:imageView]; //兩秒后開始一個持續(xù)一分鐘的動畫 [UIView animateWithDuration:1 delay:2 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ imageView.frame=CGRectMake(80, 100, 160, 160); } completion:nil];}

使用上面UIView封裝的方法進(jìn)行動畫設(shè)置固然十分方便,但是具體動畫如何實現(xiàn)我們是不清楚的,而且上面的代碼還有一些問題是無法解決的,例如:如何控制動畫的暫停?如何進(jìn)行動畫的組合?。。。

這里就需要了解iOS的核心動畫Core Animation(包含在Quartz Core框架中)。在iOS中核心動畫分為幾類:基礎(chǔ)動畫、關(guān)鍵幀動畫、動畫組、轉(zhuǎn)場動畫。各個類的關(guān)系大致如下: 這里寫圖片描述 CAAnimation:核心動畫的基礎(chǔ)類,不能直接使用,負(fù)責(zé)動畫運(yùn)行時間、速度的控制,本身實現(xiàn)了CAMediaTiming協(xié)議。

CAPropertyAnimation:屬性動畫的基類(通過屬性進(jìn)行動畫設(shè)置,注意是可動畫屬性),不能直接使用。

CAAnimationGroup:動畫組,動畫組是一種組合模式設(shè)計,可以通過動畫組來進(jìn)行所有動畫行為的統(tǒng)一控制,組中所有動畫效果可以并發(fā)執(zhí)行。

CATransition:轉(zhuǎn)場動畫,主要通過濾鏡進(jìn)行動畫效果設(shè)置。

CABasicAnimation:基礎(chǔ)動畫,通過屬性修改進(jìn)行動畫參數(shù)控制,只有初始狀態(tài)和結(jié)束狀態(tài)。

CAKeyframeAnimation:關(guān)鍵幀動畫,同樣是通過屬性進(jìn)行動畫參數(shù)控制,但是同基礎(chǔ)動畫不同的是它可以有多個狀態(tài)控制。

基礎(chǔ)動畫、關(guān)鍵幀動畫都屬于屬性動畫,就是通過修改屬性值產(chǎn)生動畫效果,開發(fā)人員只需要設(shè)置初始值和結(jié)束值,中間的過程動畫(又叫“補(bǔ)間動畫”)由系統(tǒng)自動計算產(chǎn)生。和基礎(chǔ)動畫不同的是關(guān)鍵幀動畫可以設(shè)置多個屬性值,每兩個屬性中間的補(bǔ)間動畫由系統(tǒng)自動完成,因此從這個角度而言基礎(chǔ)動畫又可以看成是有兩個關(guān)鍵幀的關(guān)鍵幀動畫。

基礎(chǔ)動畫

在開發(fā)過程中很多情況下通過基礎(chǔ)動畫就可以滿足開發(fā)需求,前面例子中使用的UIView代碼塊進(jìn)行圖像放大縮小的演示動畫也是基礎(chǔ)動畫(在iOS7中UIView也對關(guān)鍵幀動畫進(jìn)行了封裝),只是UIView裝飾方法隱藏了更多的細(xì)節(jié)。如果不使用UIView封裝的方法,動畫創(chuàng)建一般分為以下幾步:

1.初始化動畫并設(shè)置動畫屬性

2.設(shè)置動畫屬性初始值(可以省略)、結(jié)束值以及其他動畫屬性

3.給圖層添加動畫

下面以一個移動動畫為例進(jìn)行演示,在這個例子中點(diǎn)擊屏幕哪個位置落花將飛向哪里。

- (void)viewDidLoad { [super viewDidLoad]; //設(shè)置背景(注意這個圖片其實在根圖層) UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; //自定義一個圖層 _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer.contents=(id)[UIImage imageNamed:@"petal.png"].CGImage; [self.view.layer addSublayer:_layer];}#pragma mark 移動動畫-(void)translatonAnimation:(CGPoint)location{ //1.創(chuàng)建動畫并指定動畫屬性 CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"position"]; //2.設(shè)置動畫屬性初始值和結(jié)束值// basicAnimation.fromValue=[NSNumber numberWithInteger:50];//可以不設(shè)置,默認(rèn)為圖層初始狀態(tài) basicAnimation.toValue=[NSValue valueWithCGPoint:location]; //設(shè)置其他動畫屬性 basicAnimation.duration=5.0;//動畫時間5秒 //basicAnimation.repeatCount=HUGE_VALF;//設(shè)置重復(fù)次數(shù),HUGE_VALF可看做無窮大,起到循環(huán)動畫的效果 // basicAnimation.removedOnCompletion=NO;//運(yùn)行一次是否移除動畫 //3.添加動畫到圖層,注意key相當(dāng)于給動畫進(jìn)行命名,以后獲得該動畫時可以使用此名稱獲取 [_layer addAnimation:basicAnimation forKey:@"KCBasicAnimation_Translation"];}#pragma mark 點(diǎn)擊事件-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touch=touches.anyObject; CGPoint location= [touch locationInView:self.view]; //創(chuàng)建并開始動畫 [self translatonAnimation:location];}

關(guān)鍵幀動畫

熟悉Flash開發(fā)的朋友對于關(guān)鍵幀動畫應(yīng)該不陌生,這種動畫方式在flash開發(fā)中經(jīng)常用到。關(guān)鍵幀動畫就是在動畫控制過程中開發(fā)者指定主要的動畫狀態(tài),至于各個狀態(tài)間動畫如何進(jìn)行則由系統(tǒng)自動運(yùn)算補(bǔ)充(每兩個關(guān)鍵幀之間系統(tǒng)形成的動畫稱為“補(bǔ)間動畫”),這種動畫的好處就是開發(fā)者不用逐個控制每個動畫幀,而只要關(guān)心幾個關(guān)鍵幀的狀態(tài)即可。

關(guān)鍵幀動畫開發(fā)分為兩種形式:一種是通過設(shè)置不同的屬性值進(jìn)行關(guān)鍵幀控制,另一種是通過繪制路徑進(jìn)行關(guān)鍵幀控制。后者優(yōu)先級高于前者,如果設(shè)置了路徑則屬性值就不再起作用。

對于前面的落花動畫效果而言其實落花的過程并不自然,很顯然實際生活中它不可能沿著直線下落,這里我們不妨通過關(guān)鍵幀動畫的values屬性控制它在下落過程中的屬性。

- (void)viewDidLoad { [super viewDidLoad]; //設(shè)置背景(注意這個圖片其實在根圖層) UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; //自定義一個圖層 _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer.contents=(id)[UIImage imageNamed:@"petal.png"].CGImage; [self.view.layer addSublayer:_layer]; //創(chuàng)建動畫 [self translationAnimation];}#pragma mark 1關(guān)鍵幀動畫-(void)translationAnimation{ //1.創(chuàng)建關(guān)鍵幀動畫并設(shè)置動畫屬性 CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; //2.設(shè)置關(guān)鍵幀,這里有四個關(guān)鍵幀 NSValue *key1=[NSValue valueWithCGPoint:_layer.position];//對于關(guān)鍵幀動畫初始值不能省略 NSValue *key2=[NSValue valueWithCGPoint:CGPointMake(80, 220)]; NSValue *key3=[NSValue valueWithCGPoint:CGPointMake(45, 300)]; NSValue *key4=[NSValue valueWithCGPoint:CGPointMake(55, 400)]; NSArray *values=@[key1,key2,key3,key4]; keyframeAnimation.values=values; //設(shè)置其他屬性 keyframeAnimation.duration=8.0; keyframeAnimation.beginTime=CACurrentMediaTime()+2;//設(shè)置延遲2秒執(zhí)行 //3.添加動畫到圖層,添加動畫后就會執(zhí)行動畫 [_layer addAnimation:keyframeAnimation forKey:@"KCKeyframeAnimation_Position"];}#pragma mark 2關(guān)鍵幀動畫貝塞爾曲線-(void)translationAnimation{ //1.創(chuàng)建關(guān)鍵幀動畫并設(shè)置動畫屬性 CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; //2.設(shè)置路徑 //繪制貝塞爾曲線 CGPathRef path=CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, _layer.position.x, _layer.position.y);//移動到起始點(diǎn) CGPathAddCurveToPoint(path, NULL, 160, 280, -30, 300, 55, 400);//繪制二次貝塞爾曲線 keyframeAnimation.path=path;//設(shè)置path屬性 CGPathRelease(path);//釋放路徑對象 //設(shè)置其他屬性 keyframeAnimation.duration=8.0; keyframeAnimation.beginTime=CACurrentMediaTime()+5;//設(shè)置延遲2秒執(zhí)行 //3.添加動畫到圖層,添加動畫后就會執(zhí)行動畫 [_layer addAnimation:keyframeAnimation forKey:@"KCKeyframeAnimation_Position"];}

動畫組

實際開發(fā)中一個物體的運(yùn)動往往是復(fù)合運(yùn)動,單一屬性的運(yùn)動情況比較少,但恰恰屬性動畫每次進(jìn)行動畫設(shè)置時一次只能設(shè)置一個屬性進(jìn)行動畫控制(不管是基礎(chǔ)動畫還是關(guān)鍵幀動畫都是如此),這樣一來要做一個復(fù)合運(yùn)動的動畫就必須創(chuàng)建多個屬性動畫進(jìn)行組合。對于一兩種動畫的組合或許處理起來還比較容易,但是對于更多動畫的組合控制往往會變得很麻煩,動畫組的產(chǎn)生就是基于這樣一種情況而產(chǎn)生的。動畫組是一系列動畫的組合,凡是添加到動畫組中的動畫都受控于動畫組,這樣一來各類動畫公共的行為就可以統(tǒng)一進(jìn)行控制而不必單獨(dú)設(shè)置,而且放到動畫組中的各個動畫可以并發(fā)執(zhí)行,共同構(gòu)建出復(fù)雜的動畫效果。

動畫組使用起來并不復(fù)雜,首先單獨(dú)創(chuàng)建單個動畫(可以是基礎(chǔ)動畫也可以是關(guān)鍵幀動畫),然后將基礎(chǔ)動畫添加到動畫組,最后將動畫組添加到圖層即可。

前面關(guān)鍵幀動畫部分,路徑動畫看起來效果雖然很流暢,但是落花本身的旋轉(zhuǎn)運(yùn)動沒有了,這里不妨將基礎(chǔ)動畫部分的旋轉(zhuǎn)動畫和路徑關(guān)鍵幀動畫進(jìn)行組合使得整個動畫看起來更加的和諧、順暢。

- (void)viewDidLoad { [super viewDidLoad]; //設(shè)置背景(注意這個圖片其實在根圖層) UIImage *backgroundImage=[UIImage imageNamed:@"background.jpg"]; self.view.backgroundColor=[UIColor colorWithPatternImage:backgroundImage]; //自定義一個圖層 _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 10, 20); _layer.position=CGPointMake(50, 150); _layer.contents=(id)[UIImage imageNamed:@"petal.png"].CGImage; [self.view.layer addSublayer:_layer]; //創(chuàng)建動畫 [self groupAnimation];}#pragma mark 基礎(chǔ)旋轉(zhuǎn)動畫-(CABasicAnimation *)rotationAnimation{ CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; CGFloat toValue=M_PI_2*3; basicAnimation.toValue=[NSNumber numberWithFloat:M_PI_2*3];// basicAnimation.duration=6.0; basicAnimation.autoreverses=true; basicAnimation.repeatCount=HUGE_VALF; basicAnimation.removedOnCompletion=NO; [basicAnimation setValue:[NSNumber numberWithFloat:toValue] forKey:@"KCBasicAnimationProperty_ToValue"]; return basicAnimation;}#pragma mark 關(guān)鍵幀移動動畫-(CAKeyframeAnimation *)translationAnimation{ CAKeyframeAnimation *keyframeAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; CGPoint endPoint= CGPointMake(55, 400); CGPathRef path=CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, _layer.position.x, _layer.position.y); CGPathAddCurveToPoint(path, NULL, 160, 280, -30, 300, endPoint.x, endPoint.y); keyframeAnimation.path=path; CGPathRelease(path); [keyframeAnimation setValue:[NSValue valueWithCGPoint:endPoint] forKey:@"KCKeyframeAnimationProperty_EndPosition"]; return keyframeAnimation;}#pragma mark 創(chuàng)建動畫組-(void)groupAnimation{ //1.創(chuàng)建動畫組 CAAnimationGroup *animationGroup=[CAAnimationGroup animation]; //2.設(shè)置組中的動畫和其他屬性 CABasicAnimation *basicAnimation=[self rotationAnimation]; CAKeyframeAnimation *keyframeAnimation=[self translationAnimation]; animationGroup.animations=@[basicAnimation,keyframeAnimation]; animationGroup.delegate=self; animationGroup.duration=10.0;//設(shè)置動畫時間,如果動畫組中動畫已經(jīng)設(shè)置過動畫屬性則不再生效 animationGroup.beginTime=CACurrentMediaTime()+5;//延遲五秒執(zhí)行 //3.給圖層添加動畫 [_layer addAnimation:animationGroup forKey:nil];}#pragma mark - 代理方法#pragma mark 動畫完成-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ CAAnimationGroup *animationGroup=(CAAnimationGroup *)anim; CABasicAnimation *basicAnimation=animationGroup.animations[0]; CAKeyframeAnimation *keyframeAnimation=animationGroup.animations[1]; CGFloat toValue=[[basicAnimation valueForKey:@"KCBasicAnimationProperty_ToValue"] floatValue]; CGPoint endPoint=[[keyframeAnimation valueForKey:@"KCKeyframeAnimationProperty_EndPosition"] CGPointValue]; [CATransaction begin]; [CATransaction setDisableActions:YES]; //設(shè)置動畫最終狀態(tài) _layer.position=endPoint; _layer.transform=CATransform3DMakeRotation(toValue, 0, 0, 1); [CATransaction commit];}

轉(zhuǎn)場動畫

轉(zhuǎn)場動畫就是從一個場景以動畫的形式過渡到另一個場景。轉(zhuǎn)場動畫的使用一般分為以下幾個步驟:

1.創(chuàng)建轉(zhuǎn)場動畫

2.設(shè)置轉(zhuǎn)場類型、子類型(可選)及其他屬性

3.設(shè)置轉(zhuǎn)場后的新視圖并添加動畫到圖層

下表列出了常用的轉(zhuǎn)場類型(注意私有API是蘋果官方?jīng)]有公開的動畫類型,但是目前通過仍然可以使用)

這里寫圖片描述

另外對于支持方向設(shè)置的動畫類型還包含子類型:

這里寫圖片描述

實現(xiàn)一個圖片瀏覽器轉(zhuǎn)場功能

- (void)viewDidLoad { [super viewDidLoad]; //定義圖片控件 _imageView=[[UIImageView alloc]init]; _imageView.frame=[UIScreen mainScreen].applicationFrame; _imageView.contentMode=UIViewContentModeScaleaspectFit; _imageView.image=[UIImage imageNamed:@"0.jpg"];//默認(rèn)圖片 [self.view addSubview:_imageView]; //添加手勢 UISwipeGestureRecognizer *leftSwipeGesture=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)]; leftSwipeGesture.direction=UISwipeGestureRecognizerDirectionLeft; [self.view addGestureRecognizer:leftSwipeGesture]; UISwipeGestureRecognizer *rightSwipeGesture=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)]; rightSwipeGesture.direction=UISwipeGestureRecognizerDirectionRight; [self.view addGestureRecognizer:rightSwipeGesture];}#pragma mark 向左滑動瀏覽下一張圖片-(void)leftSwipe:(UISwipeGestureRecognizer *)gesture{ [self transitionAnimation:YES];}#pragma mark 向右滑動瀏覽上一張圖片-(void)rightSwipe:(UISwipeGestureRecognizer *)gesture{ [self transitionAnimation:NO];}#pragma mark 轉(zhuǎn)場動畫-(void)transitionAnimation:(BOOL)isNext{ //1.創(chuàng)建轉(zhuǎn)場動畫對象 CATransition *transition=[[CATransition alloc]init]; //2.設(shè)置動畫類型,注意對于蘋果官方?jīng)]公開的動畫類型只能使用字符串,并沒有對應(yīng)的常量定義 transition.type=@"cube"; //設(shè)置子類型 if (isNext) { transition.subtype=kCATransitionFromRight; }else{ transition.subtype=kCATransitionFromLeft; } //設(shè)置動畫時常 transition.duration=1.0f; //3.設(shè)置轉(zhuǎn)場后的新視圖添加轉(zhuǎn)場動畫 _imageView.image=[self getImage:isNext]; [_imageView.layer addAnimation:transition forKey:@"KCTransitionAnimation"];}#pragma mark 取得當(dāng)前圖片-(UIImage *)getImage:(BOOL)isNext{ if (isNext) { _currentIndex=(_currentIndex+1)%IMAGE_COUNT; }else{ _currentIndex=(_currentIndex-1+IMAGE_COUNT)%IMAGE_COUNT; } NSString *imageName=[NSString stringWithFormat:@"%i.jpg",_currentIndex]; return [UIImage imageNamed:imageName];}

逐幀動畫

前面介紹了核心動畫中大部分動畫類型,但是做過動畫處理的朋友都知道,在動畫制作中還有一種動畫類型“逐幀動畫”。說到逐幀動畫相信很多朋友第一個想到的就是UIImageView,通過設(shè)置UIImageView的animationImages屬性,然后調(diào)用它的startAnimating方法去播放這組圖片。當(dāng)然這種方法在某些場景下是可以達(dá)到逐幀的動畫效果,但是它也存在著很大的性能問題,并且這種方法一旦設(shè)置完圖片中間的過程就無法控制了。當(dāng)然,也許有朋友會想到利用iOS的定時器NSTimer定時更新圖片來達(dá)到逐幀動畫的效果。這種方式確實可以解決UIImageView一次性加載大量圖片的問題,而且讓播放過程可控,唯一的缺點(diǎn)就是定時器方法調(diào)用有時可能會因為當(dāng)前系統(tǒng)執(zhí)行某種比較占用時間的任務(wù)造成動畫連續(xù)性出現(xiàn)問題。

雖然在核心動畫沒有直接提供逐幀動畫類型,但是卻提供了用于完成逐幀動畫的相關(guān)對象CADisplayLink。CADisplayLink是一個計時器,但是同NSTimer不同的是,CADisplayLink的刷新周期同屏幕完全一致。例如在iOS中屏幕刷新周期是60次/秒,CADisplayLink刷新周期同屏幕刷新一致也是60次/秒,這樣一來使用它完成的逐幀動畫(又稱為“時鐘動畫”)完全感覺不到動畫的停滯情況。

在iOS開篇“IOS開發(fā)系列–IOS程序開發(fā)概覽”中就曾說過:iOS程序在運(yùn)行后就進(jìn)入一個消息循環(huán)中(這個消息循環(huán)稱為“主運(yùn)行循環(huán)”),整個程序相當(dāng)于進(jìn)入一個死循環(huán)中,始終等待用戶輸入。將CADisplayLink加入到主運(yùn)行循環(huán)隊列后,它的時鐘周期就和主運(yùn)行循環(huán)保持一致,而主運(yùn)行循環(huán)周期就是屏幕刷新周期。在CADisplayLink加入到主運(yùn)行循環(huán)隊列后就會循環(huán)調(diào)用目標(biāo)方法,在這個方法中更新視圖內(nèi)容就可以完成逐幀動畫。

當(dāng)然這里不得不強(qiáng)調(diào)的是逐幀動畫性能勢必較低,但是對于一些事物的運(yùn)動又不得不選擇使用逐幀動畫,例如人的運(yùn)動,這是一個高度復(fù)雜的運(yùn)動,基本動畫、關(guān)鍵幀動畫是不可能解決的。所大家一定要注意在循環(huán)方法中盡可能的降低算法復(fù)雜度,同時保證循環(huán)過程中內(nèi)存峰值盡可能低。下面以一個魚的運(yùn)動為例為大家演示一下逐幀動畫。

- (void)viewDidLoad { [super viewDidLoad]; //設(shè)置背景 self.view.layer.contents=(id)[UIImage imageNamed:@"bg.png"].CGImage; //創(chuàng)建圖像顯示圖層 _layer=[[CALayer alloc]init]; _layer.bounds=CGRectMake(0, 0, 87, 32); _layer.position=CGPointMake(160, 284); [self.view.layer addSublayer:_layer]; //由于魚的圖片在循環(huán)中會不斷創(chuàng)建,而10張魚的照片相對都很小 //與其在循環(huán)中不斷創(chuàng)建UIImage不如直接將10張圖片緩存起來 _images=[NSMutableArray array]; for (int i=0; i<10; ++i) { NSString *imageName=[NSString stringWithFormat:@"fish%i.png",i]; UIImage *image=[UIImage imageNamed:imageName]; [_images addObject:image]; } //定義時鐘對象 CADisplayLink *displayLink=[CADisplayLink displayLinkWithTarget:self selector:@selector(step)]; //添加時鐘對象到主運(yùn)行循環(huán) [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];}#pragma mark 每次屏幕刷新就會執(zhí)行一次此方法(每秒接近60次)-(void)step{ //定義一個變量記錄執(zhí)行次數(shù) static int s=0; //每秒執(zhí)行6次 if (++s%10==0) { UIImage *image=_images[_index]; _layer.contents=(id)image.CGImage;//更新圖片 _index=(_index+1)%IMAGE_COUNT; }}
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 张家口市| 杭锦后旗| 蒙自县| 栖霞市| 德昌县| 平乐县| 宝山区| 佛坪县| 和顺县| 宽城| 土默特左旗| 奉化市| 名山县| 保康县| 烟台市| 南宁市| 桂林市| 额济纳旗| 旬阳县| 禹州市| 大悟县| 松滋市| 郁南县| 罗定市| 老河口市| 东平县| 新民市| 黑山县| 类乌齐县| 晋宁县| 阳曲县| 琼海市| 奇台县| 华蓥市| 茶陵县| 衡阳县| 确山县| 昭苏县| 泰宁县| 长春市| 阿图什市|