轉(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常用的屬性:
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; }}新聞熱點(diǎn)
疑難解答