動畫在APP開發過程中還是經常出現,將花幾天的時間對Facebook開源動畫庫 POP進行簡單的學習;本文主要針對的是POPBasicAnimation運用;實例源代碼已經上傳至gitHub,地址:https://github.com/wujunyang/facebookPopTest Pop Gi
動畫在APP開發過程中還是經常出現,將花幾天的時間對Facebook開源動畫庫 POP進行簡單的學習;本文主要針對的是POPBasicAnimation運用;實例源代碼已經上傳至gitHub,地址:https://github.com/wujunyang/facebookPopTest
Pop Github : https://github.com/facebook/pop
Pop比較全的實例:https://github.com/kevinzhow/pop-handapp
Popping -Pop案例 : https://github.com/schneiderandre/popping
POP使用教程: https://github.com/maxmyers/FacebookPop
POP預設支持三種動畫 但同時也支持自定義動畫
POPBasicAnimation //基本動畫
POPSpringAnimation //類似彈簧一般的動畫效果
POPDecayAnimation //過阻尼效果,衰減效果
POPCustomAnimation //自定義動畫
一:POPBasicAnimation運用
實例1:創建一個動畫效果,關於視圖透明度的變化,從全透明經過五秒的時間變成alpha為1的不透明效果;此處運用到的POPBasicAnimation類;
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor=[UIColor whiteColor]; //1:初始化一個視圖塊 if (self.myView==nil) { self.myView=[[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)]; self.myView.backgroundColor=[UIColor redColor]; self.myView.alpha=0; [self.view addSubview:self.myView]; } //創建一個POPBasicAnimation動畫 POPBasicAnimation *basicAnimation=[POPBasicAnimation animationWithPropertyNamed:kPOPViewAlpha]; basicAnimation.fromValue=@(0); basicAnimation.toValue=@(1); basicAnimation.duration=5; //設置動畫的間隔時間 預設是0.4秒 basicAnimation.repeatCount=HUGE_VALF; //重覆次數 HUGE_VALF設置為無限次重覆 [self.myView pop_addAnimation:basicAnimation forKey:@"myViewAnimation"]; }
其實POP創建動畫的步驟分為三步,a:創建相應的動畫類 b:增加相應的屬性 c:附加到相應的對象上;
上面實例中kPOPViewAlpha是POP為我們封裝好的一個關於透明度的動畫效果;加上屬性就滿足我們的要求;從而也引出POP中一個很關鍵的類POPAnimatableProperty,裡面定義的一些常量在今後的運用中非常關鍵;
我們可以簡單看一下POPAnimatableProperty裡面定義的一些常量,因為主要針對IOS方面,所以就選出IOS相關的內容:
/** Common CALayer property names. */ extern NSString * const kPOPLayerBackgroundColor; extern NSString * const kPOPLayerBounds; extern NSString * const kPOPLayerCornerRadius; extern NSString * const kPOPLayerBorderWidth; extern NSString * const kPOPLayerBorderColor; extern NSString * const kPOPLayerOpacity; extern NSString * const kPOPLayerPosition; extern NSString * const kPOPLayerPositionX; extern NSString * const kPOPLayerPositionY; extern NSString * const kPOPLayerRotation; extern NSString * const kPOPLayerRotationX; extern NSString * const kPOPLayerRotationY; extern NSString * const kPOPLayerScaleX; extern NSString * const kPOPLayerScaleXY; extern NSString * const kPOPLayerScaleY; extern NSString * const kPOPLayerSize; extern NSString * const kPOPLayerSubscaleXY; extern NSString * const kPOPLayerSubtranslationX; extern NSString * const kPOPLayerSubtranslationXY; extern NSString * const kPOPLayerSubtranslationY; extern NSString * const kPOPLayerSubtranslationZ; extern NSString * const kPOPLayerTranslationX; extern NSString * const kPOPLayerTranslationXY; extern NSString * const kPOPLayerTranslationY; extern NSString * const kPOPLayerTranslationZ; extern NSString * const kPOPLayerZPosition; extern NSString * const kPOPLayerShadowColor; extern NSString * const kPOPLayerShadowOffset; extern NSString * const kPOPLayerShadowOpacity; extern NSString * const kPOPLayerShadowRadius; /** Common CAShapeLayer property names. */ extern NSString * const kPOPShapeLayerStrokeStart; extern NSString * const kPOPShapeLayerStrokeEnd; extern NSString * const kPOPShapeLayerStrokeColor; extern NSString * const kPOPShapeLayerFillColor; extern NSString * const kPOPShapeLayerLineWidth; extern NSString * const kPOPShapeLayerLineDashPhase; /** Common NSLayoutConstraint property names. */ extern NSString * const kPOPLayoutConstraintConstant; #if TARGET_OS_IPHONE /** Common UIView property names. */ extern NSString * const kPOPViewAlpha; extern NSString * const kPOPViewBackgroundColor; extern NSString * const kPOPViewBounds; extern NSString * const kPOPViewCenter; extern NSString * const kPOPViewFrame; extern NSString * const kPOPViewScaleX; extern NSString * const kPOPViewScaleXY; extern NSString * const kPOPViewScaleY; extern NSString * const kPOPViewSize; extern NSString * const kPOPViewTintColor; /** Common UIScrollView property names. */ extern NSString * const kPOPScrollViewContentOffset; extern NSString * const kPOPScrollViewContentSize; extern NSString * const kPOPScrollViewZoomScale; extern NSString * const kPOPScrollViewContentInset; extern NSString * const kPOPScrollViewScrollIndicatorInsets; /** Common UITableView property names. */ extern NSString * const kPOPTableViewContentOffset; extern NSString * const kPOPTableViewContentSize; /** Common UICollectionView property names. */ extern NSString * const kPOPCollectionViewContentOffset; extern NSString * const kPOPCollectionViewContentSize; /** Common UINavigationBar property names. */ extern NSString * const kPOPNavigationBarBarTintColor; /** Common UIToolbar property names. */ extern NSString * const kPOPToolbarBarTintColor; /** Common UITabBar property names. */ extern NSString * const kPOPTabBarBarTintColor; /** Common UILabel property names. */ extern NSString * const kPOPLabelTextColor; #else /** Common NSView property names. */ extern NSString * const kPOPViewFrame; extern NSString * const kPOPViewBounds; extern NSString * const kPOPViewAlphaValue; extern NSString * const kPOPViewFrameRotation; extern NSString * const kPOPViewFrameCenterRotation; extern NSString * const kPOPViewBoundsRotation; /** Common NSWindow property names. */ extern NSString * const kPOPWindowFrame; extern NSString * const kPOPWindowAlphaValue; extern NSString * const kPOPWindowBackgroundColor; #endif
其實常量對應到其每個UIKIT的一個屬性上,下麵把部分列出來,就可以瞭解到動畫效果是針對什麼屬性進行
NSString * const kPOPLayerBackgroundColor = @"backgroundColor"; //背景色 NSString * const kPOPLayerBounds = @"bounds"; //坐標 NSString * const kPOPLayerCornerRadius = @"cornerRadius"; //圓形 值越大,角就越圓 NSString * const kPOPLayerBorderWidth = @"borderWidth"; //邊框寬度 NSString * const kPOPLayerBorderColor = @"borderColor"; //邊框色 NSString * const kPOPLayerOpacity = @"opacity"; //透明度 NSString * const kPOPLayerPosition = @"position"; //位置 position是相對於屏幕的 NSString * const kPOPLayerPositionX = @"positionX"; NSString * const kPOPLayerPositionY = @"positionY"; NSString * const kPOPLayerRotation = @"rotation"; //旋轉 NSString * const kPOPLayerRotationX = @"rotationX"; NSString * const kPOPLayerRotationY = @"rotationY"; NSString * const kPOPLayerScaleX = @"scaleX"; //縮放繫數 NSString * const kPOPLayerScaleXY = @"scaleXY"; //XY縮放繫數 NSString * const kPOPLayerScaleY = @"scaleY"; //Y縮放繫數 NSString * const kPOPLayerSize = @"size"; //大小 NSString * const kPOPLayerSubscaleXY = @"subscaleXY"; NSString * const kPOPLayerSubtranslationX = @"subtranslationX"; NSString * const kPOPLayerSubtranslationXY = @"subtranslationXY"; NSString * const kPOPLayerSubtranslationY = @"subtranslationY"; NSString * const kPOPLayerSubtranslationZ = @"subtranslationZ"; NSString * const kPOPLayerTranslationX = @"translationX"; //X軸平移量 NSString * const kPOPLayerTranslationXY = @"translationXY"; //XY軸平移量 NSString * const kPOPLayerTranslationY = @"translationY"; //Y軸平移量 NSString * const kPOPLayerTranslationZ = @"translationZ"; //Z軸平移量 NSString * const kPOPLayerZPosition = @"zPosition"; //遮擋屬性 NSString * const kPOPLayerShadowColor = @"shadowColor"; //設置陰影 NSString * const kPOPLayerShadowOffset = @"shadowOffset"; //陰影偏移 NSString * const kPOPLayerShadowOpacity = @"shadowOpacity"; //陰影透明度 NSString * const kPOPLayerShadowRadius = @"shadowRadius"; //陰影半徑 // CAShapeLayer NSString * const kPOPShapeLayerStrokeStart = @"shapeLayer.strokeStart";//strokeStart 動畫的fromValue = 0,toValue = 1 表示從路徑的0位置畫到1 怎麼畫是按照清除開始的位置也就是清除0 一直清除到1 效果就是一條路徑慢慢的消失 strokeStart 動畫的fromValue = 1,toValue = 0 表示從路徑的1位置畫到0 怎麼畫是按照清除開始的位置也就是1 這樣開始的路徑是空的(即都被清除掉了)一直清除到0 效果就是一條路徑被反方向畫出來 NSString * const kPOPShapeLayerStrokeEnd = @"shapeLayer.strokeEnd";// strokeEnd 動畫的fromValue = 0,toValue = 1 表示 這裡我們分3個點說明動畫的順序 strokeEnd從結尾開始清除 首先整條路徑先清除後2/3,接著清除1/3 效果就是正方向畫出路徑 strokeEnd 動畫的fromValue = 1,toValue = 0 效果就是反方向路徑慢慢消失 NSString * const kPOPShapeLayerStrokeColor = @"shapeLayer.strokeColor"; //畫筆的色 NSString * const kPOPShapeLayerFillColor = @"shapeLayer.fillColor"; NSString * const kPOPShapeLayerLineWidth = @"shapeLayer.lineWidth"; //線的寬度 NSString * const kPOPShapeLayerLineDashPhase = @"shapeLayer.lineDashPhase";
從上面的源代碼不難發現,其實針對不同的UIKit都有一些相應的常量,比如在UIView中就有我們上面實例中出現的kPOPViewAlpha;因為POP動畫是針對對象的,所以很多的控制項都可以做出相應的動畫效果;CALayer、CAShapeLayer、UIView中相關的常量大部分控制項都可以使用;
實例2:創建一個動畫效果,實現一個視圖在延遲2s後經過5秒的時間X軸從50移到300位置的動畫效果;
//2:初始化一個視圖塊 if (self.myXView==nil) { self.myXView=[[UIView alloc]initWithFrame:CGRectMake(50, 210, 50, 50)]; self.myXView.backgroundColor=[UIColor blueColor]; [self.view addSubview:self.myXView]; } //創建一個POPBasicAnimation動畫 X軸的變化 從50移到300位置 POPBasicAnimation *anBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionX]; anBasic.toValue = @(300); anBasic.beginTime = CACurrentMediaTime() + 2.0f; //可以用來設置動畫延遲執行時間,若想延遲2s,就設置為CACurrentMediaTime()+2,CACurrentMediaTime()為圖層的當前時間 anBasic.duration=5;//設置動畫的間隔時間 預設是0.4秒 [self.myXView pop_addAnimation:anBasic forKey:@"myBackColorViewAnimation”];
實例3:創建一個動畫效果,實現視圖的背影色經過5秒後從黑色變成黃色的動畫效果;
//3:初始化一個視圖塊 if (self.myBackColorView==nil) { self.myBackColorView=[[UIView alloc]initWithFrame:CGRectMake(250, 100, 50, 50)]; self.myBackColorView.backgroundColor=[UIColor blackColor]; [self.view addSubview:self.myBackColorView]; } //創建一個POPBasicAnimation動畫 視圖的背影色從黑色經過5秒後漸進變成黃色 POPBasicAnimation *anBackGroundBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPViewBackgroundColor]; anBackGroundBasic.toValue=[UIColor yellowColor]; anBackGroundBasic.duration=5; [self.myBackColorView pop_addAnimation:anBackGroundBasic forKey:@"myBackColorViewAnimation”];
從上面三個實例可以發現,其實toValue或FormValue的值都是根據動畫屬性類型來定義,因為它們都是id型;這也決定它們可以是任何類型的值,只要符合我們要求就行;
除了上面那些常用的屬性外,還有一個運行CAMediaTimingFunction:速度控制函數屬性;四種如下:
kCAMediaTimingFunctionLinear(線性):勻速,給你一個相對靜態的感覺
kCAMediaTimingFunctionEaseIn(漸進):動畫緩慢進入,然後加速離開
kCAMediaTimingFunctionEaseOut(漸出):動畫全速進入,然後減速的到達目的地
kCAMediaTimingFunctionEaseInEaseOut(漸進漸出):動畫緩慢的進入,中間加速,然後減速的到達目的地。這個是預設的動畫行為。
實例4:創建一個POPBasicAnimation動畫 視圖中心以kCAMediaTimingFunctionLinear直線運行到中心點為100,64
//4:初始化一個視圖塊 if (self.mytimingFunctionLinearView==nil) { self.mytimingFunctionLinearView=[[UIView alloc]initWithFrame:CGRectMake(0, 300, 50, 50)]; self.mytimingFunctionLinearView.backgroundColor=[UIColor greenColor]; [self.view addSubview:self.mytimingFunctionLinearView]; } //創建一個POPBasicAnimation動畫 視圖中心以kCAMediaTimingFunctionLinear直線運行到中心點為100,64 POPBasicAnimation *anLinearBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter]; anLinearBasic.toValue=[NSValue valueWithCGPoint:CGPointMake(100, 64)]; anLinearBasic.duration=5; anLinearBasic.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; [self.mytimingFunctionLinearView pop_addAnimation:anLinearBasic forKey:@"myLinearBasic"];
實例5:創建一個POPBasicAnimation動畫 視圖中心以kCAMediaTimingFunctionEaseInEaseOut直線運行到中心點為200,64
//5:初始化一個視圖塊 if (self.mytimingFunctionEaseInEaseOutView==nil) { self.mytimingFunctionEaseInEaseOutView=[[UIView alloc]initWithFrame:CGRectMake(100, 300, 50, 50)]; self.mytimingFunctionEaseInEaseOutView.backgroundColor=[UIColor grayColor]; [self.view addSubview:self.mytimingFunctionEaseInEaseOutView]; } //創建一個POPBasicAnimation動畫 視圖中心以kCAMediaTimingFunctionEaseInEaseOut直線運行到中心點為200,64 POPBasicAnimation *anEaseInEaseOutBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter]; anEaseInEaseOutBasic.toValue=[NSValue valueWithCGPoint:CGPointMake(200, 64)]; anEaseInEaseOutBasic.duration=5; anEaseInEaseOutBasic.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; [self.mytimingFunctionEaseInEaseOutView pop_addAnimation:anEaseInEaseOutBasic forKey:@"mytimingFunctionEaseInEaseOutView”];
POP比較好的一點是保留了動畫結束後的狀態,通過block回調。如下麵的實例視圖塊的大小會被變成100*100
實例6:創建一個POPBasicAnimation動畫 讓視圖塊的大小從50*50 慢慢變到100*100
//6:初始化一個視圖塊 if (self.mySizeView==nil) { self.mySizeView=[[UIView alloc]initWithFrame:CGRectMake(250, 300, 50, 50)]; self.mySizeView.backgroundColor=[UIColor redColor]; [self.view addSubview:self.mySizeView]; } //創建一個POPBasicAnimation動畫 讓視圖塊的大小從50*50 慢慢變到100*100 POPBasicAnimation *ansizeBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPViewSize]; ansizeBasic.toValue=[NSValue valueWithCGSize:CGSizeMake(100, 100)]; ansizeBasic.duration=5; ansizeBasic.repeatCount=HUGE_VALF; [self.mySizeView pop_addAnimation:ansizeBasic forKey:@"mySizeView”];
setCompletionBlock可以在動畫完成後做一些其它的操作;
實例7:創建一個POPBasicAnimation動畫 讓視圖塊的大小從60*30 慢慢變到100*100 動畫完成後又有一個動畫變成60*30
//7:初始化一個Label if (self.myLabel==nil) { self.myLabel=[[UILabel alloc]initWithFrame:CGRectMake(50, 300, 60, 30)]; self.myLabel.backgroundColor=[UIColor redColor]; self.myLabel.textAlignment=NSTextAlignmentCenter; self.myLabel.textColor=[UIColor whiteColor]; self.myLabel.alpha=1; self.myLabel.text=@"Label"; [self.view addSubview:self.myLabel]; } //創建一個POPBasicAnimation動畫 讓視圖塊的大小從60*30 慢慢變到100*100 動畫完成後又有一個動畫變成60*30 POPBasicAnimation* anLabelBasic = [POPBasicAnimation animationWithPropertyNamed:kPOPViewSize]; anLabelBasic.duration=3.0; anLabelBasic.toValue = [NSValue valueWithCGSize:CGSizeMake(100, 100)]; anLabelBasic.timingFunction =[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; [anLabelBasic setCompletionBlock:^(POPAnimation *ani, BOOL fin) { if (fin) { NSLog(@"self.myLabel.frame=%@",NSStringFromCGRect(self.myLabel.frame)); POPBasicAnimation *newLabelAnimation=[POPBasicAnimation animationWithPropertyNamed:kPOPViewSize]; newLabelAnimation.duration=3.0; newLabelAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(60, 30)]; newLabelAnimation.timingFunction =[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; [self.myLabel pop_addAnimation:newLabelAnimation forKey:@"newMyLabelAnimation"]; } }]; [self.myLabel pop_addAnimation:anLabelBasic forKey:@"myLabelAnimation"];
實例8:增加一個動畫 類似心跳的效果,把動畫封裝在方法裡面,方便進行遞歸調用;
@property(nonatomic)CALayer *myCriLayer; @property (nonatomic) BOOL animated; 初始化代碼: //8:初始化一個CALayer層 if (self.myCriLayer==nil) { self.myCriLayer=[CALayer layer]; [self.myCriLayer pop_removeAllAnimations]; self.myCriLayer.opacity = 1.0; self.myCriLayer.transform = CATransform3DIdentity; [self.myCriLayer setMasksToBounds:YES]; [self.myCriLayer setBackgroundColor:[UIColor colorWithRed:0.16 green:0.72 blue:1 alpha:1].CGColor]; [self.myCriLayer setCornerRadius:15.0f]; [self.myCriLayer setBounds:CGRectMake(0.0f, 0.0f, 30.0f, 30.0f)]; self.myCriLayer.position = CGPointMake(self.view.center.x, 380.0); [self.view.layer addSublayer:self.myCriLayer]; } //增加一個動畫 類似心跳的效果 [self performAnimation]; 把動畫封裝在方法裡面,方便進行遞歸調用; -(void)performAnimation { [self.myCriLayer pop_removeAllAnimations]; POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY]; if (self.animated) { anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)]; }else{ anim.toValue = [NSValue valueWithCGPoint:CGPointMake(2.0, 2.0)]; } anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; //不同的類型 心跳會不一樣 self.animated = !self.animated; //使每次都有區別 anim.completionBlock = ^(POPAnimation *anim, BOOL finished) { if (finished) { [self performAnimation]; //當動畫結束後又遞歸調用,讓它產生一種心跳的效果 } }; [self.myCriLayer pop_addAnimation:anim forKey:@"Animation"]; }
這樣的方式可以在今後很多重覆的動畫中進行遞歸運用;
對於forKey是為了可以管理相應的動畫,比如移除動畫之類的,可以簡單瞭解一下官方的實例
POPSpringAnimation *anim = [POPSpringAnimation animation]; ... [layer pop_addAnimation:anim forKey:@"myKey”]; 移除: [layer pop_removeAnimationForKey:@"myKey”];
也可以刪除這個上面所有的動畫:
[layer pop_removeAllAnimations]; 可以判斷是否存在 anim = [layer pop_animationForKey:@"myKey"]; if (anim) { /* update to value to new destination */ anim.toValue = @(42.0); } else { /* create and start a new animation */ .... }
當添加類似[myView pop_addAnimation:animation forKey:@"myKey"];的動畫時,如果你用相同的key添加其他動畫,那麼新添加的動畫將會取代先前的動畫。
二:Pop Animation相比於Core Animation的優點
Pop Animation應用於CALayer時,在動畫運行的任何時刻,layer和其presentationLayer的相關屬性值始終保持一致,而Core Animation做不到。
Pop Animation可以應用任何NSObject的對象,而Core Aniamtion必須是CALayer。