本教程源码Animations 作者 YouXianMing,建议配合源码项目食用
Facebook pop动画框架简易教程请移步 Facebook 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;
两个方法,传入四个位置点参数生成。 注:上图中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
实现的思路是,定时改变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];
}
我们可以看到,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;
然后通过生成随机数的方式,用定时器定时改变,同时随机改变了颜色。所以总共使用了三个Spring动画。
相同原理的Demo还有Easing-圆环动画
只是这例子中用了作者自己封装的YXEasing
类。
总结
非线性动画对于要精益求精交互工程师来说,是一把剑利的刃。放在iOS5时代可能因为设备性能等问题,还是把双刃剑,但现在来说,已经完全是提升APP动效交互的利器了。
相关阅读: 缓动函数速查表
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。