聊聊动画引擎 pop
iOS可以通过CADisplayLink实现自定义动画引擎,pop就是基于此实现的,而且比原生Core Animation更强大好用。譬如当ViewController侧滑返回的时候,系统会将Core Animation的动画会停止,而基于CADisplayLink实现的动画则不会停止,因而可以实现类似网易云音乐从播放页侧滑时hold住专辑封面图旋转的效果。
八一八魔性的pop
1、实用的宏
#define POP_ARRAY_COUNT(x) sizeof(x) / sizeof(x[0])
#define FB_PROPERTY_GET(stype, property, ctype) \
- (ctype)property { \
return ((stype *)_state)->property; \
}
#define FB_PROPERTY_SET(stype, property, mutator, ctype, ...) \
- (void)mutator (ctype)value { \
if (value == ((stype *)_state)->property) \
return; \
((stype *)_state)->property = value; \
__VA_ARGS__ \
}
#define FB_PROPERTY_SET_OBJ_COPY(stype, property, mutator, ctype, ...) \
- (void)mutator (ctype)value { \
if (value == ((stype *)_state)->property) \
return; \
((stype *)_state)->property = [value copy]; \
__VA_ARGS__ \
}
2、判定值的数据类型
pop定义了支持的值的数据类型
const POPValueType kPOPAnimatableSupportTypes[10] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueEdgeInsets, kPOPValueColor, kPOPValueSCNVector3, kPOPValueSCNVector4};
通过@encode指令,将给定类型编码的内部字符串与objcType对比,得到值的数据类型
static bool FBCompareTypeEncoding(const char *objctype, POPValueType type)
{
switch (type)
{
case kPOPValueFloat:
return (strcmp(objctype, @encode(float)) == 0
|| strcmp(objctype, @encode(double)) == 0
);
case kPOPValuePoint:
return (strcmp(objctype, @encode(CGPoint)) == 0
#if !TARGET_OS_IPHONE
|| strcmp(objctype, @encode(NSPoint)) == 0
#endif
);
case kPOPValueSize:
return (strcmp(objctype, @encode(CGSize)) == 0
#if !TARGET_OS_IPHONE
|| strcmp(objctype, @encode(NSSize)) == 0
#endif
);
case kPOPValueRect:
return (strcmp(objctype, @encode(CGRect)) == 0
#if !TARGET_OS_IPHONE
|| strcmp(objctype, @encode(NSRect)) == 0
#endif
);
case kPOPValueEdgeInsets:
#if TARGET_OS_IPHONE
return strcmp(objctype, @encode(UIEdgeInsets)) == 0;
#else
return false;
#endif
case kPOPValueAffineTransform:
return strcmp(objctype, @encode(CGAffineTransform)) == 0;
case kPOPValueTransform:
return strcmp(objctype, @encode(CATransform3D)) == 0;
case kPOPValueRange:
return strcmp(objctype, @encode(CFRange)) == 0
|| strcmp(objctype, @encode (NSRange)) == 0;
case kPOPValueInteger:
return (strcmp(objctype, @encode(int)) == 0
|| strcmp(objctype, @encode(unsigned int)) == 0
|| strcmp(objctype, @encode(short)) == 0
|| strcmp(objctype, @encode(unsigned short)) == 0
|| strcmp(objctype, @encode(long)) == 0
|| strcmp(objctype, @encode(unsigned long)) == 0
|| strcmp(objctype, @encode(long long)) == 0
|| strcmp(objctype, @encode(unsigned long long)) == 0
);
case kPOPValueSCNVector3:
#if SCENEKIT_SDK_AVAILABLE
return strcmp(objctype, @encode(SCNVector3)) == 0;
#else
return false;
#endif
case kPOPValueSCNVector4:
#if SCENEKIT_SDK_AVAILABLE
return strcmp(objctype, @encode(SCNVector4)) == 0;
#else
return false;
#endif
default:
return false;
}
}
3、将值的数据类型标准化为Vector
举个CGRect类型的例子:
case kPOPValueRect:
vec = Vector::new_cg_rect([value CGRectValue]);
Vector *Vector::new_cg_rect(const CGRect &r)
{
Vector *v = new Vector(4);
v->_values[0] = r.origin.x;
v->_values[1] = r.origin.y;
v->_values[2] = r.size.width;
v->_values[3] = r.size.height;
return v;
}
通过Vector的两个参数size_t _count;、CGFloat *_values;将给定的类型抽象出来,实现解耦。此外还有一个好处,当创建属性动画为kPOPLayerBounds,但toValue属性赋值的是一个NSNumber,得益于_values是数组指针,并不会引发数组越界导致的crash,只是动画效果不可预期。
4、基于NSRunLoop的动画更新机制
- (void)_scheduleProcessPendingList
{
// see WebKit for magic numbers, eg http://trac.webkit.org/changeset/166540
static const CFIndex CATransactionCommitRunLoopOrder = 2000000;
static const CFIndex POPAnimationApplyRunLoopOrder = CATransactionCommitRunLoopOrder - 1;
// lock
OSSpinLockLock(&_lock);
if (!_pendingListObserver) {
__weak POPAnimator *weakSelf = self;
_pendingListObserver = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopBeforeWaiting | kCFRunLoopExit, false, POPAnimationApplyRunLoopOrder, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
[weakSelf _processPendingList];
});
if (_pendingListObserver) {
CFRunLoopAddObserver(CFRunLoopGetMain(), _pendingListObserver, kCFRunLoopCommonModes);
}
}
// unlock
OSSpinLockUnlock(&_lock);
}
在主线程RunLoop中添加观察者,监听了kCFAllocatorDefault、kCFRunLoopBeforeWaiting、kCFRunLoopExit事件,在收到回调的时候,处理_pendingList里的动画。
5、更新动画的回调数组
static POPStaticAnimatablePropertyState _staticStates[] =
{
/* CALayer */
{kPOPLayerBackgroundColor,
^(CALayer *obj, CGFloat values[]) {
POPCGColorGetRGBAComponents(obj.backgroundColor, values);
},
^(CALayer *obj, const CGFloat values[]) {
CGColorRef color = POPCGColorRGBACreate(values);
[obj setBackgroundColor:color];
CGColorRelease(color);
},
kPOPThresholdColor
},
{kPOPLayerBounds,
^(CALayer *obj, CGFloat values[]) {
values_from_rect(values, [obj bounds]);
},
^(CALayer *obj, const CGFloat values[]) {
[obj setBounds:values_to_rect(values)];
},
kPOPThresholdPoint
},
...
封装不同的动画行为,实现类似模板模式,只需统一调用,即可更新动画
// write value
write(obj, currentVec->data());
6、动画插值的动态实现
switch (type) {
case kPOPAnimationSpring:
advanced = advance(time, dt, obj);
break;
case kPOPAnimationDecay:
advanced = advance(time, dt, obj);
break;
case kPOPAnimationBasic: {
advanced = advance(time, dt, obj);
computedProgress = true;
break;
}
case kPOPAnimationCustom: {
customFinished = [self _advance:obj currentTime:time elapsedTime:dt] ? false : true;
advanced = true;
break;
}
default:
break;
}
可以看出总共有四种动画插值的算法,以kPOPAnimationBasic为例:
bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) {
// default timing function
if (!timingFunction) {
((POPBasicAnimation *)self).timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
}
// solve for normalized time, aka progresss [0, 1]
CGFloat p = 1.0f;
if (duration > 0.0f) {
// cap local time to duration
CFTimeInterval t = MIN(time - startTime, duration) / duration;
p = POPTimingFunctionSolve(timingControlPoints, t, SOLVE_EPS(duration));
timeProgress = t;
} else {
timeProgress = 1.;
}
// interpolate and advance
interpolate(valueType, valueCount, fromVec->data(), toVec->data(), currentVec->data(), p);
progress = p;
clampCurrentValue();
return true;
}
依照给定的timingFunction,使用POPTimingFunctionSolve计算贝塞尔曲线的变化率,再通过混合计算#define MIX(a, b, f) ((a) + (f) * ((b) - (a))),最终得到动画的插值。
小结
pop中还有很多有意思的地方,譬如TransformationMatrix里的矩阵操作,这里就暂且不挖WebCore底层了。简而言之,无论性能(c++混编)、易用、容错,pop都有着作为引擎该有的特性,而它所暴露的和Core Animation相似的接口也让人极易上手!
聊聊动画引擎 pop的更多相关文章
- POP动画引擎中Layer与CALayer的一点区别
POP动画引擎是facebook提供的一个开源框架, 可以实现很多的动画效果, 这里就不一一介绍啦, 有兴趣的童鞋请移步: https://github.com/facebook/pop 下面简单的讲 ...
- iOS动画——弹窗动画(pop动画)
用pop动画简单实现弹窗的缩放和渐变,感觉这个动画常用,就写一下博客 pop动画是Facebook推出的动画引擎,请自行到GitHub上搜索下载拖拽导入xcode项目中. 更多pop动画使用和原理可网 ...
- SpriteSheet精灵动画引擎
SpriteSheet精灵动画引擎 本文介绍Flash中SpriteSheet精灵序列图与其它渲染方式的性能对比.SpriteSheet的原理及注意实现,最后实现了一个精灵序列图的渲染引擎.本文的 ...
- 第四十二课:基于CSS的动画引擎
由于低版本浏览器不支持css3 animation,因此我们需要根据浏览器来选择不同的动画引擎.如果浏览器支持css3 animation,那么就使用此动画引擎,如果不支持,就使用javascript ...
- [译]理解 Windows UI 动画引擎
本文译自 Nick Waggoner 的 "Understand what’s possible with the Windows UI Animation Engine",已获原 ...
- 基于canvas与原生JS的H5动画引擎
前一段时间项目组里有一些H5动画的需求,由于没有专业的前端人员,便交由我这个做后台的研究相关的H5动画技术. 通过初步调研,H5动画的实现大概有以下几种方式: 1.基于css实现 这种方式比较简单易学 ...
- Xcode7.3.1中通过最新的CocoaPod安装pop动画引擎
CocoaPod是一个用ruby实现,用于方便的管理Xcode中第三方插件的管理器.用它我们可以很方便的安装和升级插件而不用担心破坏原有的项目. 而pop是一个用于实现App中动画的引擎,它是由Fac ...
- 用POP动画引擎实现弹簧动画(POPSpringAnimation)
效果图: #import "ViewController.h" #import <POP.h> @interface ViewController () @proper ...
- 用POP动画引擎实现衰减动画(POPDecayAnimation)
效果图: #import "ViewController.h" #import <POP.h> @interface ViewController () @end @i ...
随机推荐
- mac 上iterm终端显示中文为乱码解决方案
1.首先需要去设置下iterm,的终端编码方式为utf-8 检查方案为:iterm - > perferences - > Terminal ->Character Encoding ...
- WPF编程学习——动画
前言 使用动画,是增强用户体验的一种有效的手段.合理的动画,可以让应用程序的界面看起来更加自然.真实.流畅.舒适,更有效地向用户展现信息,用户也更容易接受.同时也增加了软件使用的乐趣,提高用户粘度.( ...
- MS-DOS 7.10完整安装版(含图文安装程序)
大家知道,要想学习或使用DOS,安装一个DOS并进行实际操作是非常必要的.MS-DOS 7.10是一个非常好且强大实用的操作系统,而且兼容性和性能都十分强.要在系统中安装MS-DOS 7.10,可以使 ...
- cmd find命令
find 作用:从文件中收索字符串 格式:find 参数 "字符串" 路径\文件名 参数: /V 显示所有未包含指定字符串的行. /C 仅显示包含字符串的行数. /N 显示行号. ...
- WMS
Web地图位置服务 Web地图服务(Web map service)利用具有地理空间位置信息的数据制作地图.其中将地图定义为地理数据可视的表现.这个规范定义了三个操作:GetCapabitities返 ...
- HDU 5667 Sequence 矩阵快速幂
官方题解: 观察递推式我们可以发现,所有的fi都是a的幂次,所以我们可以对fi取一个以a为底的log,gi=loga fi 那么递推式变gi=b+c∗gi−1+ ...
- EF架构随心所欲打造属于你自己的DbModel【转】
前言 我们都知道EF可以生成Dbmodel,系统生成的Model有时候并不是我们想要的,如何我们要生成自己的Model,那么久需要我们手动的去修改T4模版,T4是对“Text Template Tra ...
- Upgrading to EF6
In previous versions of EF the code was split between core libraries (primarily System.Data.Entity.d ...
- (转载)链表环中的入口点 编程之美 leecode 学习
http://www.cnblogs.com/hiddenfox/p/3408931.html 说的很细 /** * Definition for singly-linked list. * clas ...
- oracle 分区表和分区索引
很复杂的样子,自己都没有看完,以备后用 http://hi.baidu.com/jsshm/item/cbfed8491d3863ee1e19bc3e ORACLE分区表.分区索引ORACLE对于分区 ...