核心动画编程指南CoreAnimationProgrammingGuide-iOS
1有关核心动画
1.1概览
1.1.1CoreAnimation管理应用的内容
核心是layerobjects,
1.1.2更改layer触发动画
Likeviews,layerobjectshaveaboundsrectangle,apositiononscreen,anopacity,atransform,andmanyothervisually-orientedpropertiesthatcanbemodified.更改这些属性的时候有隐式动画,可以明确指定动画行为。
1.1.3layer可以组织成层级结构
1.1.4action让你更改图层的默认行为
隐式layer动画是使用actionobjects。可以创建自己的actionobjects,实现自定义动画,或者也能实现其他类型的行为。
1.2如果使用这个文档
1.3预备工作
先熟悉ViewProgrammingGuideforiOS.
核心动画基础
layer提供绘图和动画的基础
Layerobjects对核心。layer只是管理内容和可视化属性,所以可以将layer想成model对象
基于layer的绘图模型
对于view中调用drawRect:方法,非常的损耗,因为这在线程上使用CPU。核心动画通过在硬件上缓存位图来达到同样或相似的效果。
基于layer的动画
layer对象定义自己的几何
layer也有像view有的一些属性,framebounds,并且也有类似anchorpoing(锚点)这种view没有的属性。
layer使用两种类型的坐标系
point-basedcoordinatesystems和unitcoordinatesystems
通常使用point-based坐标系指定layer的大小和位置,
unitcoordinatesystem(单位坐标系)是用来表示当layer的大小变化的时候哪些属性可能改变。可以认为单位坐标系指定所有可能变化值的百分比。
锚点影响几何操作
layer可以在三维空间中操作
CoreAnimationFunctionsReference.
layer树反映了动画状态的不同方面
有3个layer对象集合:
modellayertree中的对象是模型对象,存储动画的目标值
presentationtree包含动画运行中的值。你应该从来都不要去修改这个tree中的对象。使用这些对象读取当前动画的值,或者使用这些值开始新的动画。
rendertree中的对象执行实际的动画,这是核心动画私有的
layer和view之间的关系
layer不是view的替代品,不能单独靠layer对象创建一个可视化的界面。layer提供了view的基础。layer使得view内容的绘制和动画更加有效,并且动画有较高的帧率,就是更流畅。layer不能处理事件,不能绘制内容,不能参与到响应链等等。所以应用必须有一个或多个view来处理这种交互
设置layer对象
激活核心动画支持
更改与视图相关的layer对象
改变UIView使用的layerclass
重写layerClass类方法返回想要替换的类对象。
指定view的layer类
+(Class)layerClass{
return[CAMetalLayerclass];
}
ChangingtheLayerClassUsedByNSView
不同的layer类提供专属行为
CALayer子类及其用法
给layer提供内容
3种方式给layer的位图提供数据:
直接给layer对象的contents属性赋值一个image对象。这是最好的方法
给layer赋值一个代理对象,并让代理绘制layer的内容。(适合内容周期性的变化,比如随着view变化)
定义一个layer子类,并重写一个它的绘制方法
给layer内容设置图像
将image赋值给layer必须是CGImageRef类型。
使用代理给layer提供内容
代理实现displayLayer:方法
-(void)displayLayer:(CALayer)theLayer{
//Checkthevalueofsomestateproperty
if(self.displayYesImage){
//DisplaytheYesimage
theLayer.contents=[someHelperObjectloadStateYesImage];
}
else{
//DisplaytheNoimage
theLayer.contents=[someHelperObjectloadStateNoImage];
}
}
代理实现drawLayer:inContext:方法
-(void)drawLayer:(CALayer)theLayerinContext:(CGContextRef)theContext{
CGMutablePathRefthePath=CGPathCreateMutable();
CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
CGPathAddCurveToPoint(thePath,
NULL,
15.f,250.0f,
295.0f,250.0f,
295.0f,15.0f);
CGContextBeginPath(theContext);
CGContextAddPath(theContext,thePath);
CGContextSetLineWidth(theContext,5);
CGContextStrokePath(theContext);
//Releasethepath
CFRelease(thePath);
}
通过子类给layer提供内容
重写layer的display方法,并使用它直接设置contents属性
重写layer的drawInContext:方法,并使用它来绘制图像内容
调整提供的内容
layer的contentsGravity属性模式的设置是kCAGravityResize常量。
高分辨率图像
调整图层的视觉风格和外观
layer有自己的背景和边界
layer支持半径圆角
layer支持内建阴影
OSX的view添加过滤效果
iOS不能给layer对象添加过滤器
对于OSX性能影响的layer重回策略
给layer添加自定义属性
AnimatingLayerContent
修改layer属性,达到简单动画效果
精确的动画,需要创建一个CABasicAnimation对象,使用这个对象来配置参数。
CABasicAnimationfadeAnim=[CABasicAnimationanimationWithKeyPath:@"opacity"];
fadeAnim.fromValue=[NSNumbernumberWithFloat:1.0];
fadeAnim.toValue=[NSNumbernumberWithFloat:0.0];
fadeAnim.duration=1.0;
[theLayeraddAnimation:fadeAnimforKey:@"opacity"];
//Changetheactualdatavalueinthelayertothefinalvalue.
theLayer.opacity=0.0;
使用关键帧动画来改变layer的属性
//createaCGPaththatimplementstwoarcs(abounce)
CGMutablePathRefthePath=CGPathCreateMutable();
CGPathMoveToPoint(thePath,NULL,74.0,74.0);
CGPathAddCurveToPoint(thePath,NULL,74.0,500.0,
320.0,500.0,
320.0,74.0);
CGPathAddCurveToPoint(thePath,NULL,320.0,500.0,
566.0,500.0,
566.0,74.0);
CAKeyframeAnimationtheAnimation;
//Createtheanimationobject,specifyingthepositionpropertyasthekeypath.
theAnimation=[CAKeyframeAnimationanimationWithKeyPath:@"position"];
theAnimation.path=thePath;
theAnimation.duration=5.0;
//Addtheanimationtothelayer.
[theLayeraddAnimation:theAnimationforKey:@"position"];
指定keyframe的值
在动画运行的时候,停止动画
removeAnimationForKey:removeAllAnimations
只能移除显示动画,不能移除隐式动画。
多个动画一起变化
//Animation1
CAKeyframeAnimationwidthAnim=[CAKeyframeAnimationanimationWithKeyPath:@"borderWidth"];
NSArraywidthValues=[NSArrayarrayWithObjects:@1.0,@10.0,@5.0,@30.0,@0.5,@15.0,@2.0,@50.0,@0.0,nil];
widthAnim.values=widthValues;
widthAnim.calculationMode=kCAAnimationPaced;
//Animation2
CAKeyframeAnimationcolorAnim=[CAKeyframeAnimationanimationWithKeyPath:@"borderColor"];
NSArraycolorValues=[NSArrayarrayWithObjects:(id)[UIColorgreenColor].CGColor,
(id)[UIColorredColor].CGColor,(id)[UIColorblueColor].CGColor,nil];
colorAnim.values=colorValues;
colorAnim.calculationMode=kCAAnimationPaced;
//Animationgroup
CAAnimationGroupgroup=[CAAnimationGroupanimation];
group.animations=[NSArrayarrayWithObjects:colorAnim,widthAnim,nil];
group.duration=5.0;
[myLayeraddAnimation:groupforKey:@"BorderChanges"];
检测动画的结束
Therearetwodifferentwaystobenotifiedaboutthestateofananimation:
AddacompletionblocktothecurrenttransactionusingthesetCompletionBlock:method.Whenalloftheanimationsinthetransactionfinish,thetransactionexecutesyourcompletionblock.
AssignadelegatetoyourCAAnimationobjectandimplementtheanimationDidStart:andanimationDidStop:finished:delegatemethods.
基于layer的view怎么做动画
iOS中修改layer的规则
[UIViewanimateWithDuration:1.0animations:^{
//Changetheopacityimplicitly.
myView.layer.opacity=0.0;
//Changethepositionexplicitly.
CABasicAnimationtheAnim=[CABasicAnimationanimationWithKeyPath:@"position"];
theAnim.fromValue=[NSValuevalueWithCGPoint:myView.layer.position];
theAnim.toValue=[NSValuevalueWithCGPoint:myNewPosition];
theAnim.duration=3.0;
[myView.layeraddAnimation:theAnimforKey:@"AnimateFrame"];
}];
建立layer层级
将layer放入layer层级中
添加、插入、移除sublayer
sublayer的位置和大小
bounds、position
myLayer.bounds=CGRectMake(0,0,100,100);
myLayer.position=CGPointMake(200,200);
1
2
重点:对于layer的宽高总是使用整数
layer层级如何影响动画
speed属性,动画速度的倍数。
调整layer层级的布局
CoreAnimationsupportsseveraloptionsforadjustingthesizeandpositionofsublayersinresponsetochangestotheirsuperlawww.shanxiwang.netyer.IniOS,thepervasiveuseoflayer-backedviewsmakesthecreationoflayerhierarchieslessimportant;onlymanuallayoutupdatesaresupported.ForOSX,severalotheroptionsareavailablethatmakeiteasiertomanageyourlayerhierarchies
sublayer和cliping
masksToBounds属性设置YES,就可以启用自动裁剪
在layer之间转换坐标值
convertPoint:fromLayer:
convertPoint:toLayer:
convertRect:fromLayer:
convertRect:toLayer:
还有convertTime:fromLayer和convertTime:toLayer
高级动画技巧
过渡动画支持更改layer可见性
创建CATransition对象,并添加给layer。
Listing5-1showsthecodeusedtocreateananimatedpushtransitionbetweentwoviews.Intheexample,bothmyView1andmyView2arelocatedatthesamepositioninthesameparentviewbutonlymyView1iscurrentlyvisible.ThepushtransitioncausesmyView1toslideouttotheleftandfadeuntilitishiddenwhilemyView2slidesinfromtherightandbecomesvisible.Updatingthehiddenpropertyofbothviewsensuresthatthevisibilityofbothviewsiscorrectattheendoftheanimation.
CATransitiontransition=[CATransitionanimation];
transition.startProgress=0;
transition.endProgress=1.0;
transition.type=kCATransitionPush;
transition.subtype=kCATransitionFromRight;
transition.duration=1.0;
//Addthetransitionanimationtobothlayers
[myView1.layeraddAnimation:transitionforKey:@"transition"];
[myView2.layeraddAnimation:transitionforKey:@"transition"];
//Finally,changethevisibilityofthelayers.
myView1.hidden=YES;
myView2.hidden=NO;
自定义动画的时间
CAMediaTiming协议。CAAnimation和CALayer都遵守了这个协议。
#import
#import
#import
/TheCAMediaTimingprotocolisimplementedbylayersandanimations,it
modelsahierarchicaltimingsystem,witheachobjectdescribingthe
mappingfromtimevaluesintheobject''sparenttolocaltime.
Absolutetimeisdefinedasmachtimeconvertedtoseconds.The
CACurrentMediaTimefunctionisprovidedasaconvenienceforqueryingthe
currentabsolutetime.
Theconversionfromparenttimetolocaltimehastwostages:
1.conversionto"activelocaltime".Thisincludesthepointat
whichtheobjectappearsintheparent''stimeline,andhowfastit
playsrelativetotheparent.
2.conversionfromactiveto"basiclocaltime".Thetimingmodel
allowsforobjectstorepeattheirbasicdurationmultipletimes,
andoptionallytoplaybackwardsbeforerepeating./
@classNSString;
NS_ASSUME_NONNULL_BEGIN
@protocolCAMediaTiming
/Thebegintimeoftheobject,inrelationtoitsparentobject,if
applicable.Defaultsto0./
@propertyCFTimeIntervalbeginTime;
/Thebasicdurationoftheobject.Defaultsto0./
@propertyCFTimeIntervalduration;
/Therateofthelayer.Usedtoscaleparenttimetolocaltime,e.g.
ifrateis2,localtimeprogressestwiceasfastasparenttime.
Defaultsto1./
@propertyfloatspeed;
/Additionaloffsetinactivelocaltime.i.e.toconvertfromparent
timetptoactivelocaltimet:t=(tp-begin)speed+offset.
Oneuseofthisisto"pause"alayerbysetting`speed''tozeroand
`offset''toasuitablevalue.Defaultsto0./
@propertyCFTimeIntervaltimeOffset;
/Therepeatcountoftheobject.Maybefractional.Defaultsto0./
@propertyfloatrepeatCount;
/Therepeatdurationoftheobject.Defaultsto0./
@propertyCFTimeIntervalrepeatDuration;
/Whentrue,theobjectplaysbackwardsafterplayingforwards.Defaults
toNO./
@propertyBOOLautoreverses;
/Defineshowthetimedobjectbehavesoutsideitsactiveduration.
Localtimemaybeclampedtoeitherendoftheactiveduration,or
theelementmayberemovedfromthepresentation.Thelegalvalues
are`backwards'',`forwards'',`both''and`removed''.Defaultsto
`removed''./
@property(copy)NSStringfillMode;
@end
/`fillMode''options./
CA_EXTERNNSStringconstkCAFillModeForwards
__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
CA_EXTERNNSStringconstkCAFillModeBackwards
__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
CA_EXTERNNSStringconstkCAFillModeBoth
__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
CA_EXTERNNSStringconstkCAFillModeRemoved
__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
NS_ASSUME_NONNULL_END
得到layer的当前localtime
CFTimeIntervallocalLayerTime=[myLayerconvertTime:CACurrentMediaTime()fromLayer:nil];
1
暂停和重新开始动画
-(void)pauseLayer:(CALayer)layer{
CFTimeIntervalpausedTime=[layerconvertTime:CACurrentMediaTime()fromLayer:nil];
layer.speed=0.0;
layer.timeOffset=pausedTime;
}
-(void)resumeLayer:(CALayer)layer{
CFTimeIntervalpausedTime=[layertimeOffset];
layer.speed=1.0;
layer.timeOffset=0.0;
layer.beginTime=0.0;
CFTimeIntervaltimeSincePause=[layerconvertTime:CACurrentMediaTime()fromLayer:nil]-pausedTime;
layer.beginTime=timeSincePause;
}
显式Transactions可以更改动画参数
CATransaction类
创建显式的transaction
[CATransactionbegin];
theLayer.zPosition=200.0;
theLayer.opacity=0.0;
[CATransactioncommit];
修改动画的默认持续时间
[CATransactionbegin];
[CATransactionsetValue:[NSNumbernumberWithFloat:10.0f]
forKey:kCATransactionAnimationDuration];
//Performtheanimations
[CATransactioncommit];
嵌套显式transaction
[CATransactionbegin];//Outertransaction
//Changetheanimationdurationtotwoseconds
[CATransactionsetValue:[NSNumbernumberWithFloat:2.0f]
forKey:kCATransactionAnimationDuration];
//Movethelayertoanewposition
theLayer.position=CGPointMake(0.0,0.0);
[CATransactionbegin];//Innertransaction
//Changetheanimationdurationtofiveseconds
[CATransactionsetValue:[NSNumbernumberWithFloat:5.0f]
forKey:kCATransactionAnimationDuration];
//ChangethezPositionandopacity
theLayer.zPosition=200.0;
theLayer.opacity=0.0;
[CATransactioncommit];//Innertransaction
[CATransactioncommit];//Outertransaction
给动画添加透视
给parentlayer添加透视变化
CATransform3Dperspective=CATransform3DIdentity;
perspective.m34=-1.0/eyePosition;
//Applythetransformtoaparentlayer.
myParentLayer.sublayerTransform=perspective;
改变layer的默认行为
CAAction协议
/Action(eventhandler)protocol./
@protocolCAAction
/Calledtotriggertheeventnamed''path''onthereceiver.Theobject
(e.g.thelayer)onwhichtheeventhappenedis''anObject''.The
argumentsdictionarymaybenil,ifnon-nilitcarriesparameters
associatedwiththeevent./
-(void)runActionForKey:(NSString)eventobject:(id)anObject
arguments:(nullableNSDictionary)dict;
@end
自定义操作对象采用CAAction协议
action对象必须被安装在layer上,才能有效果
核心动画寻找action对象的顺序:
如果layer有一个delegate,并且delegate实现了actionForLayer:forKey方法,layer调用这个方法。delegate必须做下面几件事之一:
针对key返回action对象
没有它没有handletheaction就返回nil,这种情况会接着寻找
搜寻到末尾的时候立即返回NSNull对象
在layer的actions字典中寻找给定的key
在style字典中寻找包含key的actions字典(总而言之,style字典包含了一个key为actions,value也是一个字典。layer在这第二个字典中寻找给定的key)
layer调用它的defaultActionForKey:类方法
layer执行核心动画定义的隐式action
使用layer代理对象提供action
-(id)actionForLayer:(CALayer)theLayer
forKey:(NSString)theKey{
CATransitiontheAnimation=nil;
if([theKeyisEqualToString:@"contents"]){
theAnimation=[[CATransitionalloc]init];
theAnimation.duration=1.0;
theAnimation.timingFunction=[CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseIn];
theAnimation.type=kCATransitionPush;
theAnimation.subtype=kCATransitionFromRight;
}
returntheAnimation;
}
使用CATransaction类暂时禁用action
Temporarilydisablingalayer’sactions
[CATransactionbegin];
[CATransactionsetValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[aLayerremoveFromSuperlayer];
[CATransactioncommit];
提升动画性能
为OSXViews选择最佳的重绘策略
在OSX中更新layer来优化renderingpath
通用技巧和窍门
尽可能使用不透明的layer
对CAShapeLayer对象使用更简单的path
对相同layer明确设置layer内容
总是将layer的大小设置为整数值
根据需要使用异步来渲染layer
drawsAsynchronously属性
当给layer添加阴影的时候指定shadowpath
AppendixA:layerstylepropertyanimation
LayerStylePropertyAnimations
AppendixB:AnimatableProperties
AnimatableProperties
|
|