配色: 字号:
核心动画编程指南Core Animation Programming Guide
2016-09-09 | 阅:  转:  |  分享 
  
核心动画编程指南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

献花(0)
+1
(本文系网络学习天...首藏)