iOS開發(fā)UIView的Animation效果
所謂動(dòng)畫效果,就是會(huì)動(dòng)的畫,到iOS App中來說的話,就是各種UIView的移動(dòng)。 想想看,如果我們自己來實(shí)現(xiàn)所有UIView的動(dòng)畫效果,需要考慮些什么東西呢?
* 該UIView現(xiàn)在在哪兒?
* 該UIView最后會(huì)動(dòng)到哪兒?
* 該UIView以什么樣的方式移動(dòng)到那兒?
* 該動(dòng)畫持續(xù)多長(zhǎng)時(shí)間?
* 每次移動(dòng)的最小時(shí)間間隔?
* 每次最小時(shí)間間隔的移動(dòng)的應(yīng)該移動(dòng)到哪兒?
* ….
想想這是一個(gè)多么殺腦細(xì)胞的過程,尤其是每一次的動(dòng)畫過程都要重復(fù)這一折磨的過程。
還好,現(xiàn)實(shí)比想象的美好, 蘋果公司為開發(fā)者思考了上面的問題,通過使用UIKit提供的動(dòng)畫支持,開發(fā)者只需要簡(jiǎn)單的幾行代碼就能實(shí)現(xiàn)各種各樣的動(dòng)畫效果。在UIKit中,所有的動(dòng)畫效果支持的方法都在UIView類中。
首先,在UIView中有很多屬性用以描述一個(gè)UIView的狀態(tài),而動(dòng)畫就是讓UIView從一個(gè)狀態(tài)平滑的過渡到另外一個(gè)狀態(tài)的過程。這些屬性有:
屬性名 |
作用 |
frame |
控制UIView的大小和該UIView在superview中的相對(duì)位置。 |
bounds |
控制UIView的大小 |
center |
控制UIView的位置 |
transform |
控制UIView的縮放,旋轉(zhuǎn)角度等固定好中心位置之后的變化 |
alpha |
控制UIView的透明度 |
backgroundColor |
控制UIView的背景色 |
contentStretch |
控制UIView的拉伸方式 |
通過設(shè)置這些屬性,基本上就解決了動(dòng)畫中的移動(dòng)到哪兒的問題。
接著,蘋果公司在UIView中加入很多方法來方便家控制動(dòng)畫的移動(dòng)時(shí)間,以及移動(dòng)的方式。iOS3.0及之前,UIView支持的Animation方法有如下這么多:
Object-c代碼
- @interface UIView(UIViewAnimation)
- + (void)beginAnimations:(NSString *)animationID context:(void *)context; // additional context info passed to will start/did stop selectors. begin/commit can be nested
- + (void)commitAnimations; // starts up any animations when the top level animation is commited
- // no getters. if called outside animation block, these setters have no effect.
- + (void)setAnimationDelegate:(id)delegate; // default = nil
- + (void)setAnimationWillStartSelector:(SEL)selector; // default = NULL. -animationWillStart:(NSString *)animationID context:(void *)context
- + (void)setAnimationDidStopSelector:(SEL)selector; // default = NULL. -animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
- + (void)setAnimationDuration:(NSTimeInterval)duration; // default = 0.2
- + (void)setAnimationDelay:(NSTimeInterval)delay; // default = 0.0
- + (void)setAnimationStartDate:(NSDate *)startDate; // default = now ([NSDate date])
- + (void)setAnimationCurve:(UIViewAnimationCurve)curve; // default = UIViewAnimationCurveEaseInOut
- + (void)setAnimationRepeatCount:(float)repeatCount; // default = 0.0. May be fractional
- + (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses; // default = NO. used if repeat count is non-zero
- + (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState; // default = NO. If YES, the current view position is always used for new animations -- allowing animations to "pile up" on each other. Otherwise, the last end state is used for the animation (the default).
- + (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache; // current limitation - only one per begin/commit block
- + (void)setAnimationsEnabled:(BOOL)enabled; // ignore any attribute changes while set.
- + (BOOL)areAnimationsEnabled;
- @end
這些方法非常的不直觀,開發(fā)者還是需要花很多時(shí)間去思考怎么組合這些方法。但是自從iOS4.0提供塊語法支持之后,蘋果公司把動(dòng)畫效果的實(shí)現(xiàn)封裝了一下,效果立桿見影,直觀了許多,因此大家完全可以不用去看上面的那些方法,重點(diǎn)關(guān)注如下的方法:
Object-c代碼
- @interface UIView(UIViewAnimationWithBlocks)
- + (void)animateWithDuration:(NSTimeInterval)duration
- delay:(NSTimeInterval)delay
- options:(UIViewAnimationOptions)options
- animations:(void (^)(void))animations
- completion:(void (^)(BOOL finished))completion;
- + (void)animateWithDuration:(NSTimeInterval)duration
- animations:(void (^)(void))animations
- completion:(void (^)(BOOL finished))completion
- NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0
- + (void)animateWithDuration:(NSTimeInterval)duration
- animations:(void (^)(void))animations
- NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL
- + (void)transitionWithView:(UIView *)view
- duration:(NSTimeIntervl)duration
- options:(UIViewAnimationOptins)options
- animations:(void (^)(void)animations
- completion:(void (^)(BOOL finished) completion
- NS_AVAILABLE_IOS(4_0);
- + (void)transitionFromView:(UIView *)fromView
- toView:(UIView *)toView
- duration:(NSTimeInterval)duration
- options:(UIViewAnimationOptions)options
- completion:(void (^)(BOOL finished))completion
- NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview
- @end
上面的幾個(gè)方法從名字上看就非常直觀。前三個(gè)方法都可以按如下的方式直譯,只是后兩個(gè)使用了一些默認(rèn)參數(shù)而已:
Java代碼
- 做一個(gè)動(dòng)畫效果,持續(xù)時(shí)間為duration,
- 延遲delay秒開始執(zhí)行 ,
- 以options指定的方式運(yùn)行這個(gè)動(dòng)畫,
- animations塊中指定哪些UIView會(huì)參加本次動(dòng)畫效果,以及動(dòng)畫效果完成時(shí)這些UIView會(huì)是一個(gè)什么狀態(tài),
- 動(dòng)畫完成之后,執(zhí)行completion塊進(jìn)行收尾。
有了這3個(gè)方法,開發(fā)者只需要思考,初始值,結(jié)果值,持續(xù)時(shí)間,運(yùn)行方式就行了,具體的細(xì)節(jié)移動(dòng)都交給類庫。
后2個(gè)方法是用于UIView相互之間轉(zhuǎn)換的,個(gè)人覺得用處不大,因?yàn)橛蒙厦娴娜齻€(gè)方法同樣可以做到這些效果,因此略過。
關(guān)于UIView的動(dòng)畫效果支持,有2點(diǎn)值得一提
* 上面所有的方法都是類方法,當(dāng)調(diào)用這些方法之后,系統(tǒng)會(huì)新起線程執(zhí)行動(dòng)畫效果,不會(huì)阻塞主線程的執(zhí)行。
* UIView的Animation效果只支持一些簡(jiǎn)單的2D動(dòng)畫效果,復(fù)雜的大家還得研究Core Animation。
一個(gè)實(shí)戰(zhàn)例子
在我寫的一個(gè)小游戲的主機(jī)界面中,我使用了一點(diǎn)動(dòng)畫的效果,主界面的設(shè)計(jì)圖如下:
動(dòng)畫后的效果圖如下:
我想要的效果就是,加載主界面后,圖片緩緩的展開成扇形,然后游戲的菜單顯示供玩家點(diǎn)擊。
代碼如下:
首先,準(zhǔn)備動(dòng)畫前狀態(tài),讓想展示的UIView不可見:
Object-c代碼
- -(void) prepareForIntroAnimation
- {
- self.sImageView.hidden=YES;
- self.nImageView.hidden=YES;
- self.aImageView.hidden=YES;
- self.pImageView.hidden=YES;
- self.jokerImageView.hidden=YES;
- self.hostGameButton.alpha=0.0f;
- self.joinGameButton.alpha=0.0f;
- self.singlePlayerGameButton.alpha=0.0f;
- self.helpButton.alpha=0.0f;
- _buttonsEnabled = NO;
- }
然后,展示動(dòng)畫效果:
Object-c代碼
- -(void) performAnimation
- {
- //顯示UIView
- self.sImageView.hidden=NO;
- self.nImageView.hidden=NO;
- self.aImageView.hidden=NO;
- self.pImageView.hidden=NO;
- self.jokerImageView.hidden=NO;
- [UIView animateWithDuration:0.65f
- delay:0.5f
- options:UIViewAnimationOptionCurveEaseIn
- animations:^
- {
- //確定UIView的的中心位置和偏轉(zhuǎn)角度
- self.sImageView.center = CGPointMake(80.0f, 108.0f);
- self.sImageView.transform = CGAffineTransformMakeRotation(-0.22f);
- self.nImageView.center = CGPointMake(160.0f, 93.0f);
- self.nImageView.transform = CGAffineTransformMakeRotation(-0.1f);
- self.aImageView.center = CGPointMake(240.0f, 88.0f);
- self.pImageView.center = CGPointMake(320.0f, 93.0f);
- self.pImageView.transform = CGAffineTransformMakeRotation(0.1f);
- self.jokerImageView.center = CGPointMake(400.0f, 108.0f);
- self.jokerImageView.transform = CGAffineTransformMakeRotation(0.22f);
- }
- completion:nil];
- [UIView animateWithDuration:0.5f
- delay:1.0f
- options:UIViewAnimationOptionCurveEaseOut
- animations:^
- {
- //透明度設(shè)置為1,顯示游戲菜單。
- self.hostGameButton.alpha = 1.0f;
- self.joinGameButton.alpha = 1.0f;
- self.singlePlayerGameButton.alpha = 1.0f;
- self.helpButton.alpha = 1.0f;
- }
- completion:^(BOOL finished)
- {
- _buttonsEnabled = YES;
- }];
- }
另外,動(dòng)畫效果還可以使用completion的回調(diào)塊做連接,完成多個(gè)動(dòng)畫效果的連接。