Animations開源動效分析(二)POP-Stroke動畫

554843030 8年前發布 | 14K 次閱讀 iOS開發 Android開發 移動開發

來自: http://segmentfault.com/a/1190000004365988

  1. 本教程源碼 Animations 作者 YouXianMing ,建議配合源碼項目食用

  2. 非死book pop動畫框架簡易教程請移步 非死book Pop 使用指南

  3. CoreAnimation不簡易教程

  4. 如果不想看第三條的教程,也要弄明白CALayer的隱式動畫,否則看本文會疑惑,請移步 CALayer的隱式動畫和顯式動畫

CAMediaTimingFunction

今天我們來看一下研究一下 CAMediaTimingFunction 類,它是一個動畫的時間線控制類,他所控制的時間線,可以是是一條直線、曲線或者折線,如下:

這是用一個開源軟件生成的 CAMediaTimingFunction ,軟件地址是 keefo/CATweaker

可見,一般自定義的 CAMediaTimingFunction 通過調用

/* Creates a timing function modelled on a cubic Bezier curve. The end

  • points of the curve are at (0,0) and (1,1), the two points 'c1' and
  • 'c2' defined by the class instance are the control points. Thus the
  • points defining the Bezier curve are: '[(0,0), c1, c2, (1,1)]' */
  • (instancetype)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;

  • (instancetype)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;</pre>

    兩個方法,傳入四個位置點參數生成。 注:上圖中XY軸區間都是[0,1];

    這個類,在什么地方用到呢?

    1. CALayer的隱式和顯式動畫, CATransaction 有 animationTimingFunction 設置。

    2. CAKeyframeAnimation 有相關設置。

    3. CABasicAnimation 是線性的動畫,一條直線。

    4. CASpringAnimation 彈簧動畫是也是有一個特殊的走向,屬于 CAMediaTimingFunction 的特殊封裝。

    5. POP 也借用了 CAMediaTimingFunction 類實現非線性動畫。

    下面這個網站可以在線調試, cubic-bezier ,雖然是給CSS工程師用的,但是通用的。

    上圖中,藍色的方塊的運動就是線性的,紅色方塊是非線性的。

    iOS7開始,iOS系統大量引入了非線性動畫。

    上圖引用自 使用 iOS 8 Spring Animation API 創建動畫

    Spring動畫

    彈簧(Spring)動畫是一種特殊曲線的非線性動畫,因為用的地方太多,所以無論是CoreAnimation還是POP,都將其進行了封裝 CASpringAnimation , POPSpringAnimation 。

    兩者有一點區別,參考源碼中的 CASpringAnimation 和 POP-Spring動畫參數詳解

    POP-Stroke動畫

    今天我們來分析一下 POP-Stroke動畫 的源代碼,首先interface中聲明了一個 CAShapeLayer 是中心的圓, timer 是一個定時器。這個GCDTimer是作者對GCD進行的一層對象化封裝。

    @interface PopStrokeController ()

@property (nonatomic, strong) CAShapeLayer circleShape; @property (nonatomic, strong) GCDTimer timer;

@end</pre>

實現的思路是,定時改變 CAShapeLayer 的startStoke和endStoke屬性,改變圓的繪制弧度,使用POP的Spring動畫控制其改變數值。

- (void)setup {

[super setup];

self.circleShape           = [CAShapeLayer layer];
self.circleShape.strokeEnd = 0.f;
self.circleShape.lineCap   = kCALineCapRound;

StrokeCircleLayerConfigure *config = [StrokeCircleLayerConfigure new];
config.lineWidth                   = 4.f;
config.startAngle                  = 0;
config.endAngle                    = M_PI * 2;
config.radius                      = 55.f;
config.circleCenter                = self.contentView.middlePoint;
config.strokeColor                 = [UIColor cyanColor];
[config configCAShapeLayer:self.circleShape];   
[self.contentView.layer addSublayer:self.circleShape];

_timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];

[_timer event:^{

    CGFloat value1 = arc4random() % 101 / 100.f;
    CGFloat value2 = arc4random() % 101 / 100.f;

    POPSpringAnimation *strokeAnimationEnd = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeEnd];
    strokeAnimationEnd.toValue             = @(value1 > value2 ? value1 : value2);
    strokeAnimationEnd.springBounciness    = 12.f;

    POPSpringAnimation *strokeAnimationStart = [POPSpringAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeStart];
    strokeAnimationStart.toValue             = @(value1 < value2 ? value1 : value2);
    strokeAnimationStart.springBounciness    = 12.f;

    POPBasicAnimation *strokeAnimationColor  = [POPBasicAnimation animationWithPropertyNamed:kPOPShapeLayerStrokeColor];
    strokeAnimationColor.toValue             = (__bridge id)([self randomColor].CGColor);

    [self.circleShape pop_addAnimation:strokeAnimationEnd forKey:@"layerStrokeAnimation"];
    [self.circleShape pop_addAnimation:strokeAnimationStart forKey:@"layerStrokeAnimation1"];
    [self.circleShape pop_addAnimation:strokeAnimationColor forKey:@"layerStrokeAnimation2"];

} timeIntervalWithSecs:1];

[_timer start];

}

  • (UIColor *)randomColor {

    return [UIColor colorWithRed:arc4random() % 101 / 100.f

                         green:arc4random() % 101 / 100.f
                          blue:arc4random() % 101 / 100.f
                         alpha:1];
    

    }</pre>

    我們可以看到,POP支持了CALayer的所有動畫屬性,上面代碼中用的

    NSString * const kPOPShapeLayerStrokeStart = @"shapeLayer.strokeStart";
    NSString * const kPOPShapeLayerStrokeEnd = @"shapeLayer.strokeEnd";
    NSString * const kPOPShapeLayerStrokeColor = @"shapeLayer.strokeColor";

    分別對應CAShapeLayer的繪制顏色,起始比例區間。

    /* The color to fill the path's stroked outline, or nil for no stroking.

    • Defaults to nil. Animatable. */

@property(nullable) CGColorRef strokeColor;

/* These values define the subregion of the path used to draw the

  • stroked outline. The values must be in the range [0,1] with zero
  • representing the start of the path and one the end. Values in
  • between zero and one are interpolated linearly along the path
  • length. strokeStart defaults to zero and strokeEnd to one. Both are
  • animatable. */

@property CGFloat strokeStart; @property CGFloat strokeEnd;</pre>

然后通過生成隨機數的方式,用定時器定時改變,同時隨機改變了顏色。所以總共使用了三個Spring動畫。

相同原理的Demo還有 Easing-圓環動畫

只是這例子中用了作者自己封裝的 YXEasing 類。

總結

非線性動畫對于要精益求精交互工程師來說,是一把劍利的刃。放在iOS5時代可能因為設備性能等問題,還是把雙刃劍,但現在來說,已經完全是提升APP動效交互的利器了。

相關閱讀: 緩動函數速查表

</div>

 本文由用戶 554843030 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!