聊聊iOS中的動畫

Simba_LX發表於2018-07-31

####先附上文中的Demo,需要的朋友可以下載看一下

#####先簡單說一下CALayer

  • iOS 的動畫都是基於 CALayer 的,每個UIView都對應有一個CALayer。 所以修改UIView的屬性所呈現的動畫都是CALayer實現的。CALayer不能響應事件。下圖是UIView和CALyer的關係
    聊聊iOS中的動畫


#####iOS中可以實現動畫的方式,有不對的地方敬請指正 1. UIView動畫 ``` //Duration 動畫持續時間 //animations 動畫過程 [UIView animateWithDuration:<#(NSTimeInterval)#> animations:<#^(void)animations#>];
//block裡是動畫完成的回撥
[UIView animateWithDuration:<#(NSTimeInterval)#> animations:<#^(void)animations#> completion:<#^(BOOL finished)completion#>];

//delay 等待時間
//options 動畫型別
[UIView animateWithDuration:<#(NSTimeInterval)#> delay:<#(NSTimeInterval)#> options:<#(UIViewAnimationOptions)#> animations:<#^(void)animations#> completion:<#^(BOOL finished)completion#>];

//彈性動畫
//damping:阻尼,範圍0-1,阻尼越接近於0,彈性效果越明顯
//velocity:彈性復位的速度
[UIView animateWithDuration:<#(NSTimeInterval)#> delay:<#(NSTimeInterval)#> usingSpringWithDamping:<#(CGFloat)#> initialSpringVelocity:<#(CGFloat)#> options:<#(UIViewAnimationOptions)#> animations:<#^(void)animations#> completion:<#^(BOOL finished)completion#>];

//關鍵幀動畫
[UIView animateKeyframesWithDuration:<#(NSTimeInterval)#> delay:<#(NSTimeInterval)#> options:<#(UIViewKeyframeAnimationOptions)#> animations:<#^(void)animations#> completion:<#^(BOOL finished)completion#>];
複製程式碼
2. CoreAnimation
核心動畫
![](http://upload-images.jianshu.io/upload_images/292993-2e9b3c01ec9da922.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

`CAAnimation:核心動畫的基礎類,不能直接使用,負責動畫執行時間、速度的控制,本身實現了CAMediaTiming協議。`

`CAPropertyAnimation:屬性動畫的基類(通過屬性進行動畫設定,注意是可動畫屬性),不能直接使用。`

`CAAnimationGroup:動畫組,動畫組是一種組合模式設計,可以通過動畫組來進行所有動畫行為的統一控制,組中所有動畫效果可以併發執行。`

`CATransition:轉場動畫,主要通過濾鏡進行動畫效果設定。`

`CABasicAnimation:基礎動畫,通過屬性修改進行動畫引數控制,只有初始狀態和結束狀態。`

`CAKeyframeAnimation:關鍵幀動畫,同樣是通過屬性進行動畫引數控制,但是同基礎動畫不同的是它可以有多個狀態控制。`


基礎動畫、關鍵幀動畫都屬於屬性動畫,就是通過修改屬性值產生動畫效果,開發人員只需要設定初始值和結束值,中間的過程動畫(又叫“補間動畫”)由系統自動計算產生。和基礎動畫不同的是關鍵幀動畫可以設定多個屬性值,每兩個屬性中間的補間動畫由系統自動完成,因此從這個角度而言基礎動畫又可以看成是有兩個關鍵幀的關鍵幀動畫。

---

* 下面利用CABasicAnimation實現一個簡單的縮放動畫
複製程式碼

CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; scaleAnimation.duration=.3; scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; scaleAnimation.fromValue = @(1); scaleAnimation.toValue = @(1.5); scaleAnimation.fillMode = kCAFillModeForwards; scaleAnimation.removedOnCompletion = NO;
[view.layer addAnimation:scaleAnimation forKey:@"transformscale"];

`**注意點** 如果fillMode=kCAFillModeForwards和removedOnComletion=NO,那麼在動畫執行完畢後,圖層會保持顯示動畫執行後的狀態。但在實質上,圖層的屬性值還是動畫執行前的初始值,並沒有真正被改變。`

* CAKeyframeAnimation用法和CABasicAnimation類似,多了一個values屬性
* CAAnimationGroup動畫組可以把基礎動畫和關鍵幀動畫加入進animations屬性

---
在實際專案中很多需求使用UIView動畫或者基本動畫就可以實現,比如下面比較常用的縮放和彈性動畫效果

![AnimationdemoGif1.gif](http://upload-images.jianshu.io/upload_images/292993-3d1f6209124a76eb.gif?imageMogr2/auto-orient/strip)


![AnimationdemoGif.gif](http://upload-images.jianshu.io/upload_images/292993-e23badf4fdb830f9.gif?imageMogr2/auto-orient/strip)

---

####炫酷的動畫
如果想實現更炫酷一點的動畫,如雷達,波紋,咻一咻效果,時鐘,帶動畫的指示器等就需要用到UIBezierPath和CAShapeLayer,CAReplicatorLayer等知識。
下面簡單的說一下CAShapeLayer和CAReplicatorLayer
* CAShapeLayer
`普通CALayer在被初始化時是需要給一個frame值的,這個frame值一般都與給定view的bounds值一致,它本身是有形狀的,而且是矩形.
CAShapeLayer在初始化時也需要給一個frame值,但是,它本身沒有形狀,它的形狀來源於你給定的一個path,然後它去取CGPath值,它與CALayer有著很大的區別`
 
* CAShapeLayer有著幾點很重要:
`1. 它依附於一個給定的path,必須給與path,而且,即使path不完整也會自動首尾相接`
`2. strokeStart以及strokeEnd代表著在這個path中所佔用的百分比`
`3. CAShapeLayer動畫僅僅限於沿著邊緣的動畫效果,它實現不了填充效果`
複製程式碼

// 建立一個shapeLayer    CAShapeLayer *layer = [CAShapeLayer layer];    layer.frame         = showView.bounds;                // 與showView的frame一致    layer.strokeColor   = [UIColor greenColor].CGColor;   // 邊緣線的顏色    layer.fillColor     = [UIColor clearColor].CGColor;   // 閉環填充的顏色    layer.lineCap       = kCALineCapSquare;               // 邊緣線的型別  layer.path          = path.CGPath;                    // 從貝塞爾曲線獲取到形狀    layer.lineWidth     = 4.0f;                           // 線條寬度 layer.strokeStart   = 0.0f;    layer.strokeEnd     = 0.1f;   // 將layer新增進圖層    [showView.layer addSublayer:layer];


* CAReplicatorLayer
`CAReplicatorLayer可以複製自己子層的layer,並且複製的出來的layer和原來的子layer擁有相同的動效`

---
####貝塞爾曲線UIBezierPath
複製程式碼

UIBezierPath主要是用來繪製路徑的,分為一階、二階.....n階。一階是直線,二階以上才是曲線。而最終路徑的顯示還是得依靠CALayer 初始化方法一共7種 //方法1:構造bezierPath物件,一般用於自定義路徑。 [UIBezierPath bezierPath];

 //方法2:根據某個CGRect繪製路徑。
 [UIBezierPath bezierPathWithRect:<#(CGRect)#>];
 
 //方法3:根據某個CGRect繪製內切圓或橢圓(CGRect是正方形即為圓,為長方形則為橢圓)。
 [UIBezierPath bezierPathWithOvalInRect:<#(CGRect)#>];
 
 //方法4:根據某個路徑繪製路徑。
 [UIBezierPath bezierPathWithCGPath:<#(nonnull CGPathRef)#>];
 
 //方法5:繪製每個角都是圓角的矩形,引數2是半徑。
 [UIBezierPath bezierPathWithRoundedRect:<#(CGRect)#> cornerRadius:<#(CGFloat)#>];
 
 //方法6:繪製帶圓角的矩形路徑,引數2哪個角,引數3,橫、縱向半徑。
 [UIBezierPath bezierPathWithRoundedRect:<#(CGRect)#> byRoundingCorners:<#(UIRectCorner)#> cornerRadii:<#(CGSize)#>];
 
 //方法7:繪製圓弧路徑,引數1是中心點位置,引數2是半徑,引數3是開始的弧度值,引數4是結束的弧度值,引數5是是否順時針(YES是順時針方向,NO逆時針)。
 [UIBezierPath bezierPathWithArcCenter:<#(CGPoint)#> radius:<#(CGFloat)#> startAngle:<#(CGFloat)#> endAngle:<#(CGFloat)#> clockwise:<#(BOOL)#>];
 ```
複製程式碼
     自定義路徑常用api
     - (void)moveToPoint:(CGPoint)point; // 移到某個點
     - (void)addLineToPoint:(CGPoint)point; // 繪製直線
     - (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2; //繪製貝塞爾曲線
     - (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint; // 繪製規則的貝塞爾曲線
     - (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise
     // 繪製圓形曲線
     - (void)appendPath:(UIBezierPath *)bezierPath; // 拼接曲線
複製程式碼

AnimationdemoGif2.gif

  • 實現程式碼
//波紋,咻一咻,雷達效果
- (void)setup
{
    _testView=[[UIView alloc] initWithFrame:CGRectMake(30, 300, 100, 100)];
    [self.view addSubview:_testView];
    
    _testView.layer.backgroundColor = [UIColor clearColor].CGColor;
    CAShapeLayer *pulseLayer = [CAShapeLayer layer];
    pulseLayer.frame = _testView.layer.bounds;
    pulseLayer.path = [UIBezierPath bezierPathWithOvalInRect:pulseLayer.bounds].CGPath;
    pulseLayer.fillColor = [UIColor redColor].CGColor;//填充色
    pulseLayer.opacity = 0.0;
    
    CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
    replicatorLayer.frame = _testView.bounds;
    replicatorLayer.instanceCount = 4;//建立副本的數量,包括源物件。
    replicatorLayer.instanceDelay = 1;//複製副本之間的延遲
    [replicatorLayer addSublayer:pulseLayer];
    [_testView.layer addSublayer:replicatorLayer];
    
    CABasicAnimation *opacityAnima = [CABasicAnimation animationWithKeyPath:@"opacity"];
    opacityAnima.fromValue = @(0.3);
    opacityAnima.toValue = @(0.0);
    
    CABasicAnimation *scaleAnima = [CABasicAnimation animationWithKeyPath:@"transform"];
    scaleAnima.fromValue = [NSValue valueWithCATransform3D:CATransform3DScale(CATransform3DIdentity, 0.0, 0.0, 0.0)];
    scaleAnima.toValue = [NSValue valueWithCATransform3D:CATransform3DScale(CATransform3DIdentity, 1.0, 1.0, 0.0)];
    
    CAAnimationGroup *groupAnima = [CAAnimationGroup animation];
    groupAnima.animations = @[opacityAnima, scaleAnima];
    groupAnima.duration = 4.0;
    groupAnima.autoreverses = NO;
    groupAnima.repeatCount = HUGE;
    [pulseLayer addAnimation:groupAnima forKey:@"groupAnimation"];
}
複製程式碼
//利用UIBezierPath和CAShapeLayer實現不規則的圖形,並帶有動畫效果,可以在折線圖中使用
-(void)myTest{
    UIView *line=[[UIView alloc] initWithFrame:CGRectMake(0, 100, 400, 1)];
    line.backgroundColor=[UIColor grayColor];
    [self.view addSubview:line];
    
    _testView1=[[UIImageView alloc] initWithFrame:CGRectMake(0, 100, 300, 200)];
    _testView1.userInteractionEnabled=YES;
    [self.view addSubview:_testView1];
    
    
    //貝塞爾曲線,以下是4個角的位置,相對於_testView1
    CGPoint point1= CGPointMake(10, 80);
    CGPoint point2= CGPointMake(10, 200);
    CGPoint point3= CGPointMake(300, 200);
    CGPoint point4= CGPointMake(300, 80);
    
    _path=[UIBezierPath bezierPath];
    [_path moveToPoint:point1];//移動到某個點,也就是起始點
    [_path addLineToPoint:point2];
    [_path addLineToPoint:point3];
    [_path addLineToPoint:point4];
    [_path addQuadCurveToPoint:point1 controlPoint:CGPointMake(150, -30)];
    
    CAShapeLayer *shapeLayer=[CAShapeLayer layer];
    shapeLayer.path=_path.CGPath;
    shapeLayer.fillColor=[UIColor clearColor].CGColor;//填充顏色
    shapeLayer.strokeColor=[UIColor orangeColor].CGColor;//邊框顏色
    [_testView1.layer addSublayer:shapeLayer];
    
    //動畫
    CABasicAnimation *pathAniamtion = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    pathAniamtion.duration = 3;
    pathAniamtion.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    pathAniamtion.fromValue = [NSNumber numberWithFloat:0.0f];
    pathAniamtion.toValue = [NSNumber numberWithFloat:1.0];
    pathAniamtion.autoreverses = NO;
    [shapeLayer addAnimation:pathAniamtion forKey:nil];
    
    
    UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickk:)];
    [_testView1 addGestureRecognizer:tap];
    
}

-(void)clickk:(UITapGestureRecognizer *)tap{
    CGPoint point=[tap locationInView:_testView1];
    if ([_path containsPoint:point]) {
       NSLog(@"點選不規則圖形");
    }
    
}
複製程式碼

補充一--基本動畫設定引數 在動畫方法中有一個option引數,UIViewAnimationOptions型別,它是一個列舉型別,動畫引數分為三類,可以組合使用:

1.常規動畫屬性設定(可以同時選擇多個進行設定) UIViewAnimationOptionLayoutSubviews:動畫過程中保證子檢視跟隨運動。 UIViewAnimationOptionAllowUserInteraction:動畫過程中允許使用者互動。 UIViewAnimationOptionBeginFromCurrentState:所有檢視從當前狀態開始執行。 UIViewAnimationOptionRepeat:重複執行動畫。 UIViewAnimationOptionAutoreverse :動畫執行到結束點後仍然以動畫方式回到初始點。 UIViewAnimationOptionOverrideInheritedDuration:忽略巢狀動畫時間設定。 UIViewAnimationOptionOverrideInheritedCurve:忽略巢狀動畫速度設定。 UIViewAnimationOptionAllowAnimatedContent:動畫過程中重繪檢視(注意僅僅適用於轉場動畫)。  UIViewAnimationOptionShowHideTransitionViews:檢視切換時直接隱藏舊檢視、顯示新檢視,而不是將舊檢視從父檢視移除(僅僅適用於轉場動畫)UIViewAnimationOptionOverrideInheritedOptions :不繼承父動畫設定或動畫型別。 2.動畫速度控制(可從其中選擇一個設定) UIViewAnimationOptionCurveEaseInOut:動畫先緩慢,然後逐漸加速。 UIViewAnimationOptionCurveEaseIn :動畫逐漸變慢。 UIViewAnimationOptionCurveEaseOut:動畫逐漸加速。 UIViewAnimationOptionCurveLinear :動畫勻速執行,預設值。 3.轉場型別(僅適用於轉場動畫設定,可以從中選擇一個進行設定,基本動畫、關鍵幀動畫不需要設定) UIViewAnimationOptionTransitionNone:沒有轉場動畫效果。 UIViewAnimationOptionTransitionFlipFromLeft :從左側翻轉效果。 UIViewAnimationOptionTransitionFlipFromRight:從右側翻轉效果。 UIViewAnimationOptionTransitionCurlUp:向後翻頁的動畫過渡效果。    UIViewAnimationOptionTransitionCurlDown :向前翻頁的動畫過渡效果。    UIViewAnimationOptionTransitionCrossDissolve:舊檢視溶解消失顯示下一個新檢視的效果。    UIViewAnimationOptionTransitionFlipFromTop :從上方翻轉效果。    UIViewAnimationOptionTransitionFlipFromBottom:從底部翻轉效果。


補充二--keyPath layer有很多屬性,通過animationWithKeyPath修改,列舉一下常用的屬性:

聊聊iOS中的動畫
那麼怎麼知道這些屬性都有哪些呢。 1.apple官方文件 2.通過runtime 3.多看大神部落格,注意收集

####附上以上動畫的Demo,需要的朋友可以下載看一下

推薦幾篇關於動畫的部落格


相關文章