聊聊动画引擎 pop
来源:互联网 发布:百度霸屏js 编辑:程序博客网 时间:2024/05/16 10:51
聊聊动画引擎 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 = [valuecopy];\
__VA_ARGS__\
}
2、判定值的数据类型
pop定义了支持的值的数据类型
constPOPValueTypekPOPAnimatableSupportTypes[10] = {kPOPValueInteger,kPOPValueFloat,kPOPValuePoint,kPOPValueSize,kPOPValueRect,kPOPValueEdgeInsets,kPOPValueColor,kPOPValueSCNVector3,kPOPValueSCNVector4};
通过@encode指令,将给定类型编码的内部字符串与objcType对比,得到值的数据类型
staticboolFBCompareTypeEncoding(constchar*objctype,POPValueTypetype)
{
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
returnstrcmp(objctype,@encode(UIEdgeInsets)) == 0;
#else
returnfalse;
#endif
case kPOPValueAffineTransform:
returnstrcmp(objctype,@encode(CGAffineTransform)) == 0;
case kPOPValueTransform:
returnstrcmp(objctype,@encode(CATransform3D)) == 0;
case kPOPValueRange:
returnstrcmp(objctype,@encode(CFRange)) == 0
||strcmp(objctype,@encode(NSRange)) == 0;
case kPOPValueInteger:
return(strcmp(objctype,@encode(int)) == 0
||strcmp(objctype,@encode(unsignedint)) == 0
||strcmp(objctype,@encode(short)) == 0
||strcmp(objctype,@encode(unsignedshort)) == 0
||strcmp(objctype,@encode(long)) == 0
||strcmp(objctype,@encode(unsignedlong)) == 0
||strcmp(objctype,@encode(longlong)) == 0
||strcmp(objctype,@encode(unsignedlonglong)) == 0
);
case kPOPValueSCNVector3:
#if SCENEKIT_SDK_AVAILABLE
returnstrcmp(objctype,@encode(SCNVector3)) == 0;
#else
returnfalse;
#endif
case kPOPValueSCNVector4:
#if SCENEKIT_SDK_AVAILABLE
returnstrcmp(objctype,@encode(SCNVector4)) == 0;
#else
returnfalse;
#endif
default:
returnfalse;
}
}
3、将值的数据类型标准化为Vector
举个CGRect类型的例子:
case kPOPValueRect:
vec = Vector::new_cg_rect([valueCGRectValue]);
Vector*Vector::new_cg_rect(constCGRect &r)
{
Vector*v = newVector(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;
returnv;
}
通过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
staticconstCFIndexCATransactionCommitRunLoopOrder = 2000000;
staticconstCFIndexPOPAnimationApplyRunLoopOrder = CATransactionCommitRunLoopOrder - 1;
// lock
OSSpinLockLock(&_lock);
if(!_pendingListObserver){
__weakPOPAnimator*weakSelf = self;
_pendingListObserver = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault,kCFRunLoopBeforeWaiting | kCFRunLoopExit,false,POPAnimationApplyRunLoopOrder, ^(CFRunLoopObserverRefobserver,CFRunLoopActivityactivity){
[weakSelf_processPendingList];
});
if(_pendingListObserver){
CFRunLoopAddObserver(CFRunLoopGetMain(),_pendingListObserver, kCFRunLoopCommonModes);
}
}
// unlock
OSSpinLockUnlock(&_lock);
}
在主线程RunLoop中添加观察者,监听了kCFAllocatorDefault、kCFRunLoopBeforeWaiting、kCFRunLoopExit事件,在收到回调的时候,处理_pendingList里的动画。
5、更新动画的回调数组
staticPOPStaticAnimatablePropertyState_staticStates[] =
{
/* CALayer */
{kPOPLayerBackgroundColor,
^(CALayer*obj,CGFloatvalues[]){
POPCGColorGetRGBAComponents(obj.backgroundColor,values);
},
^(CALayer*obj,constCGFloatvalues[]){
CGColorRefcolor = POPCGColorRGBACreate(values);
[obj setBackgroundColor:color];
CGColorRelease(color);
},
kPOPThresholdColor
},
{kPOPLayerBounds,
^(CALayer*obj,CGFloatvalues[]){
values_from_rect(values,[objbounds]);
},
^(CALayer*obj,constCGFloatvalues[]){
[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为例:
booladvance(CFTimeIntervaltime,CFTimeIntervaldt,idobj){
// default timing function
if(!timingFunction){
((POPBasicAnimation*)self).timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
}
// solve for normalized time, aka progresss [0, 1]
CGFloatp = 1.0f;
if(duration > 0.0f){
// cap local time to duration
CFTimeIntervalt = 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();
returntrue;
}
依照给定的timingFunction,使用POPTimingFunctionSolve计算贝塞尔曲线的变化率,再通过混合计算#define MIX(a, b, f) ((a) + (f) * ((b) - (a))),最终得到动画的插值。
小结
pop中还有很多有意思的地方,譬如TransformationMatrix里的矩阵操作,这里就暂且不挖WebCore底层了。简而言之,无论性能(c++混编)、易用、容错,pop都有着作为引擎该有的特性,而它所暴露的和Core Animation相似的接口也让人极易上手!
- 聊聊动画引擎 pop
- 聊聊魔性的动画引擎pop
- 动画引擎pop
- IOS facebook 开源动画引擎 pop
- POP — Facebook开源动画引擎
- Facebook将神奇动画引擎Pop开源了
- Facebook将神奇动画引擎Pop开源了!
- facebook开源动画引擎 pop 源码阅读笔记:
- 【POP动画引擎教程 01】实现图片折叠效果
- pop动画
- pop动画
- Xcode7.3.1中通过最新的CocoaPod安装pop动画引擎
- ios push pop动画
- pop动画实践(一)
- ios pop 折叠动画
- ios pop系统动画
- Pop动画丢失问题
- 简单实用POP动画
- Linux常用指令集
- ansible学习笔记(二) -- roles
- 神奇的 BlocksKit(1):源码分析(上)
- Linux下安装nginx
- 欢迎使用CSDN-markdown编辑器
- 聊聊动画引擎 pop
- ArrayList和LinkedList的操作性能对比
- 利用pscp实现从putty远程终端复制文件到本地windows操作系统
- c++作业-5
- python xmlrpc实现二进制文件传输的代码,简单的远程调用
- Postgresql外部表的使用:file_fdw
- jax-rs简介
- VS2013 密钥 – 所有版本
- Jaxb annotation初步使用