Animations開源動效分析(二)POP-Stroke動畫
來自: http://segmentfault.com/a/1190000004365988
-
本教程源碼 Animations 作者 YouXianMing ,建議配合源碼項目食用
-
非死book pop動畫框架簡易教程請移步 非死book Pop 使用指南
-
如果不想看第三條的教程,也要弄明白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];
這個類,在什么地方用到呢?
-
CALayer的隱式和顯式動畫, CATransaction 有 animationTimingFunction 設置。
-
CAKeyframeAnimation 有相關設置。
-
CABasicAnimation 是線性的動畫,一條直線。
-
CASpringAnimation 彈簧動畫是也是有一個特殊的走向,屬于 CAMediaTimingFunction 的特殊封裝。
-
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>