iPhone/iOS Core Animation開發總結(CALayer)

來源:互聯網
上載者:User
文章目錄
  • 六.CALayer的子類們
一.重要參數

bounds,frame,position屬於基本的幾何定位,相互之間數值變化會相互影響

anchorPoint:單位參數(0-1)表示,變形(transform)時候的變換源點

zPosition:相當於css中z-index的概念,Apple建議不要用這個來替代CALayer層次設定。

cornerRadius:圓角

二.幾何變形(Transforming a Layer's Geometry)

1.用CATransform3D系列方法

        //將CGAffineTransform轉換成CATransform3D        layer1_1.transform=CATransform3DMakeAffineTransform(CGAffineTransformMakeScale(1, -1));        //CATransform3D系列方法        layer1_1.transform=CATransform3DMakeScale(-1, 1, 1);              layer1_1.transform=CATransform3DScale(CATransform3DMakeScale(-2, 1, 1), -1, 1, 1);        layer1_1.transform=CATransform3DIdentity;

2.修改CATransform3D的data structure

        CATransform3D trans=CATransform3DIdentity;        NSLog(@"%f",trans.m44);        //不能是1除以,一定要1.0除以1000(zDistance)        //wrong     trans.m34=1/100.00        trans.m34=-1.0/1000;        trans = CATransform3DTranslate(trans, 0, 0, -240);        trans = CATransform3DRotate(trans, d2r(90), 1, 0, 0);        trans = CATransform3DTranslate(trans, 0, 0, 240);        [layer1 setTransform:trans];

3.key-valre設定key Paths(rotation,scale,translation)

        [layer1 setValue:[NSNumber numberWithInt:200] forKeyPath:@"transform.translation.x"];

三.Layer數層結構(Layer-Tree Hierarchy)

1.add,insert,remove,replace來進行樹狀結構的構建

2.重設(Reposition and Resizing)layer

a)你可以通過修改第一點提到的幾個參數來調整大小。

b)needsDisplayOnBoundsChange設定YES,則在bounds變化時,自動調用setNeedsDisplay,調用layer的display的方法,或者直接顯示調用setNeedsDisplay(不能使用setNeedsDisplayInRect),也會調用自訂layer的display方法。或者是setNeesLayout,調用layer的layoutSubLayers。(PS:無法使用layoutManager和autoResizingMask方法,這個是Mac
OS上的方法。)

c)在UIView的layoutSubviews裡實現自訂layout的方法。

3.masksToBounds設定YES,則裁剪subLayers。否則不裁剪,subLayers可以超過superLayer的bounds。

4.Action

當更改layer的參數或者將layer添加,刪除,隱藏,替換時觸發

觸發方法可以是子類化CALayer,-(id<CAAction>)actionForKey:(NSString*)key;代理方式-(id<CAAction>)actionForLayer:(CALayer*) forKey:(NSString*)key

-(id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event{        CATransition *anim=nil;        if([event isEqualToString:@"contents"]){                anim=[CATransition animation];                anim.duration=2;                anim.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];                anim.type=@"cube";                anim.subtype=kCATransitionFromRight;        }        return anim;        //不執行任何動畫        //return nil;}

蘋果文檔種提供了修改sublayers預設動畫的方法

        NSMutableDictionary *cActions=[NSMutableDictionary dictionaryWithDictionary:[layer1_1 actions]];        [cActions setObject:[NSNull null] forKey:@"sublayers"];        layer1_1.actions=cActions;

實現CAAction Protocol

代理類中實現方法runActionForKey:object:arguments

-(void)runActionForKey:(NSString *)event object:(id)anObject arguments:(NSDictionary *)dict{        NSLog(@"runActionForKey:\"%@\" object:%@ arguments:%@", event, anObject, dict);        CATransition *anim=nil;        if([event isEqualToString:@"test"]){                anim=[CATransition animation];                anim.duration=2;                anim.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];                anim.type=@"cube";                anim.subtype=kCATransitionFromRight;        }        [(CALayer*)anObject addAnimation:anim forKey:@"contets"];}

觸發runActionForKey

        //添加自訂的action以及對應的觸發方法所在的代理,應該可以定義一個動畫子類(CAAnimation)        layer1.actions = [NSDictionary dictionaryWithObjectsAndKeys:[[FCLayerDelegate alloc]init], @"test", nil];        //實際觸發的地方,當設定test參數,其實最後觸發的是runActionForKey種的立方體旋轉        [layer1 setValue:[NSNumber numberWithInt:19] forKey:@"test"];

四.提供Layer內容(Providing Layer Content)

1.contents屬性設定CGImageRef

   layer1.contents=(id)image1.CGImage;

2.用delegate來提供內容

a)displayLayer:(CALayer*)

b)-(void)drawLayer:(CALayer*) inContext:(CGContextRef)

//聲明代理@interface FCLayerDeledegate : NSObject@end//實現代理@implementation FCLayerDelegate//覆蓋這個方法,就不會執行後面的方法,2者取其一,根據傳入的值來判斷下一步操作-(void)displayLayer:(CALayer *)layer{NSLog(@"%@",[layer valueForKey:@"test"]);}-(void)drawLayer:(CALayer *)ly inContext:(CGContextRef)context{ CGContextSetFillColorWithColor(context, [[UIColor redColor]CGColor]);CGContextFillRect(context, ly.bounds);}@end
//執行代碼CALayer* layer1_3=[CALayer layer];        layer1_3.delegate=[[FCLayerDelegate alloc]init];[layer1_3 setValue:@"testString" forKey:@"test"];[layer1_3 setNeedsDisplay];

ps:以上方法用於CALayer本身(非自己子類)

3) 用子類提供內容

a)display

b)drawInContext:(CGContextRef)

和前面代理模式差不多,只不過少傳layer參數,因為layer就是其本身(self);

4)內容的布局

預設情況下,內容圖片是會鋪開充滿整個layer的bounds的,如果要使得contents按照原來尺寸顯示在layer中,就要設定ContentsGravity

大致2種參數

1.位置參數,注意,ios座標是y是相反的,所以bottom就是top

2.設定鋪滿方式,3種

layer1_3.contentsGravity=kCAGravityBottomLeft;layer1_3.contents=(id)image3.CGImage;//layer1_3.contentsGravity=kCAGravityResizeAspectFill;

PS:此外contentsCenter這個屬性在鋪滿方式的參數下可以指定展開地區,文檔中指出是指定展開的範圍,但是似乎沒有作用。暫時忽略。

五.動畫

1.動畫類簇

a)CAMediaTiming protocol的主要參數

speed:執行速度,如果速度為2,則一個10秒的duration,則只需要5秒完成。子類參數相對父類參數的,如果子類是2,父類是2,則需要2.5秒完成

repeatCount|repeatDuration:重複的次數和重複的間隔 ,如果repeatCount設定成 1e100f則無限重複

fillMode:決定動畫結束時候的狀態。要和removeOnCompletion參數一起設定才有效。動畫結束後的狀態並沒有影響layer的位置,其實layer還在原來的地方沒變。

此外還有duration,autoreverses,beginTime,timeOffset

b)CAAnimation

timingFunction:指定一個CAMediaTimingFunction,有2種提供方式,一種是常量如kCAMediaTimingFunctionLinear,另外一種是自訂2個control points來定製一個時間曲線

functionWithControlPoints::::。

delegate:2個代理方法animationDidStart:和animationDidStop:finished:

2.一般動畫

任何CALayer的animated的屬性或者CTM改變時候都是動畫形式來過渡的,這個稱為implicit Animation。這裡不多做介紹

主要介紹下(Explicit Animation)顯示動畫

a)CABasicAnimation 針對某個屬性的設定變化

        CABasicAnimation *anim;        anim=[CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];        anim.duration=8;        anim.autoreverses=NO;        anim.repeatCount=2;        anim.fromValue=[NSNumber numberWithFloat:d2r(0)];        anim.toValue=[NSNumber numberWithFloat:d2r(-90)];        //  layer1.transform=CATransform3DTranslate(CATransform3DIdentity, 0, 0, 100);        [layer1 addAnimation:anim forKey:@"layer1Rotation"];

b)CAKeyframeAnimation

主要畫面格(key frame)有2種方式提供:

參數path,建立CGPathRef

path:CGPathRef 一般用於移動複雜的位置,如下例:

        CGMutablePathRef path=CGPathCreateMutable();        CGPathMoveToPoint(path, NULL, 40, 420);        CGPathAddCurveToPoint(path, NULL, 40, 40, 160, 40, 160, 420);        CGPathAddCurveToPoint(path, NULL, 160, 40, 280, 40, 280, 420);        CAKeyframeAnimation *anim=[CAKeyframeAnimation animationWithKeyPath:@"position"];        anim.path=path;        anim.duration=3;                //映像在移動過程中是否旋轉        anim.rotationMode=kCAAnimationRotateAuto;        //動畫結束時候狀態,我動畫結束在哪裡就停在哪裡        anim.removedOnCompletion = NO;        anim.fillMode=kCAFillModeForwards;        //設定keyTimes path加了2個點,所以將duration設定成了2段,前面一段快3/10,後面一段慢7/10        anim.calculationMode=kCAAnimationLinear;        anim.keyTimes=[NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0],[NSNumber numberWithFloat:0.3],[NSNumber numberWithFloat:1.0], nil];        [layer1 addAnimation:anim forKey:@"nm1"];        CGPathRelease(path);

參數values:array of objects

如果objects是CGImage,key-path是"contents"的話,則是映像切換。

        CAKeyframeAnimation *anim=[CAKeyframeAnimation animationWithKeyPath:@"contents"];        anim.duration=3;        anim.values=[NSArray arrayWithObjects:(id)image1.CGImage,(id)image2.CGImage,(id)image3.CGImage,nil];        [layer1 addAnimation:anim forKey:@"nm2"];

如果objects是CATransform3D的,key-path是“transform”,則是變換座標

        CAKeyframeAnimation *anim2=[CAKeyframeAnimation animationWithKeyPath:@"transform"];        anim2.duration=3;        anim2.repeatCount=1000;        anim2.autoreverses=YES;        CATransform3D trans=CATransform3DScale(CATransform3DIdentity, 1.5, 1.5, 1);        CATransform3D trans2=CATransform3DScale(CATransform3DIdentity, 1, 1, 1);        anim2.values=[NSArray arrayWithObjects:[NSValue valueWithCATransform3D:trans],[NSValue valueWithCATransform3D:trans2],nil];        [layer1 addAnimation:anim2 forKey:@"nm3"];

如果2個同時設定,還可以同時看到動畫效果。比方說上述2個就可以看到圖片切換並且放大和縮小的效果。
不要針對frame和size等參數設定keyframe動畫,似乎沒有效果。position是可以的。

3.動畫事務(Transaction)

        [CATransaction begin];        [CATransaction setValue:[NSNumber numberWithFloat:.5f] forKey:kCATransactionAnimationDuration];        layer1.position=CGPointMake(0, 0);        layer1.opacity=0;        [CATransaction commit];

通過事務可以修改implicit 動畫的時間,否則沒有辦法修改。

4.動畫過渡(Transition)

        //CATransition        CATransition *animation = [CATransition animation];        animation.delegate = self;        animation.duration = 2;        animation.timingFunction = UIViewAnimationCurveEaseInOut;        //animation.type = kCATransitionFade;        animation.type = @"cube";        animation.subtype = kCATransitionFromLeft;        //2個view交換        NSUInteger green = [[self.view subviews] indexOfObject:self.greenView];        NSUInteger blue = [[self.view subviews] indexOfObject:self.blueView];        [self.view exchangeSubviewAtIndex:green withSubviewAtIndex:blue];        [layer1 addAnimation:animation forKey:@"animation"];

過渡有view的過渡和layer的過渡,2者是有區別的,網上有個例子transition包含了一共12種變換,相當有用。此外還可以設定startProgress和endProgress,這樣就可以讓動畫執行到某個特定位置,比如說pageCurUp的話,就可以翻到一半,相當的酷哦!

六.CALayer的子類們

隨著iOS 5.0的更新,CALayer添加了新的成員,我稍微研究了一些,現在做下總結,有的是新的,有的則是5.0以前的。

1.CAReplicatorLayer

顧名思義,這個類是用來建立重複的layer,並且可以根據設定的參數,進行一個漸層

    //每個單元的小layers設定    CALayer *layer1 = [CALayer layer];    layer1.position = CGPointMake(10,200);    layer1.bounds = CGRectMake(0, 0, 20, 20);    layer1.backgroundColor = [[UIColor yellowColor] CGColor];    layer1.cornerRadius = 2;    layer1.shadowColor = [[UIColor blackColor] CGColor];    layer1.shadowRadius = 4.0f;    layer1.shadowOffset = CGSizeMake(0.0f, 3.0f);    layer1.shadowOpacity = .8;    layer1.opacity = 0.8;    layer1.borderColor = [[UIColor whiteColor] CGColor];    layer1.borderWidth = 2.0;    //設定父容器    CAReplicatorLayer *xLayer = [CAReplicatorLayer layer];    xLayer.instanceCount = 11;//產生多少個字元素    xLayer.instanceDelay = .2;//延遲產生    xLayer.instanceGreenOffset = -.03;//綠色位移量    xLayer.instanceRedOffset = -.02;//紅色位移量    xLayer.instanceBlueOffset = -.01;//藍色位移量    xLayer.instanceAlphaOffset = -.05;    xLayer.instanceTransform =CATransform3DMakeTranslation(25, 0, 200);//元素位移位移量    [xLayer addSublayer:layer1];//將元素加入            xLayer.preservesDepth = YES;//superLayer是否啟用3D景深計算    //設定景深    CATransform3D transform = CATransform3DIdentity;    transform.m34 = -1 / 2000.0f;    xLayer.transform=transform;

甚至可以對layer加入組合式的動畫,從而各個元素會有序的一起動畫,主要的方法如下:

這個是針對layer的instanceTransform,從而可以影響每一個cell進行同樣動畫的移動,下面是進行平移的動畫

- (CABasicAnimation *)pushAnimation {    CABasicAnimation *pushAnim =    [CABasicAnimation animationWithKeyPath:@"instanceTransform"];    pushAnim.fromValue =[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(SUBLAYER_WIDTH+INTERSPACE, 0, 0)];    pushAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(SUBLAYER_WIDTH+INTERSPACE+60, 0, 0)];    pushAnim.duration = 3.0;    pushAnim.autoreverses = YES;    pushAnim.repeatCount = HUGE_VAL;    pushAnim.timingFunction =    [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];    return pushAnim;}

2.CAEmitterLayer&CAEmitterCell

網上有很多粒子相關的代碼,比如雪花的飄動,燃燒的火焰,煙霧效果,其實都是通過這個類的設定來實現的,用法和CAReplicatorLayer差不多,主要介紹下參數

    // Configure the particle emitter to the top edge of the screenCAEmitterLayer *snowEmitter = [CAEmitterLayer layer];snowEmitter.emitterPosition = CGPointMake(self.view.bounds.size.width / 2.0, -30);//設定發射位置,這個和emitterMode有關    snowEmitter.emitterZPosition=50;//發射點z的位置,這個和emitterMode有關snowEmitter.emitterSize= CGSizeMake(self.view.bounds.size.width * 2.0, 0.0);//發射點的範圍,這個和emitterMode有關snowEmitter.emitterDepth=100;    //從線上發射    //    snowEmitter.emitterMode= kCAEmitterLayerOutline;    //snowEmitter.emitterShape= kCAEmitterLayerLine;    //從一個立方體內發射出,這樣的話雪花會有不同的大小在3D的情況下    snowEmitter.emitterMode= kCAEmitterLayerVolume;snowEmitter.emitterShape= kCAEmitterLayerCuboid;//設定發射單元CAEmitterCell *snowflake = [CAEmitterCell emitterCell];snowflake.birthRate= 3.0;//每秒發生1個snowflake.lifetime= 120.0;//存留時間為120秒snowflake.velocity= 20;//初始速度snowflake.velocityRange = 10;//初始速度的隨機範圍snowflake.yAcceleration = 10;//y軸加速度,當然還有z,x軸//snowflake.emissionRange = -0.5 * M_PI;// 發射角度範圍 ,這個參數一設定,似乎方向只能朝螢幕內,就是z的負軸        snowflake.spin=0.0;snowflake.spinRange=- 0.25 * M_PI;// 自旋轉範圍snowflake.contents= (id) [[UIImage imageNamed:@"flake"] CGImage];snowflake.color= [[UIColor colorWithRed:0.600 green:0.658 blue:0.743 alpha:1.000] CGColor];    // Make the flakes seem inset in the backgroundsnowEmitter.shadowOpacity = 1.0;snowEmitter.shadowRadius  = 0.0;snowEmitter.shadowOffset  = CGSizeMake(0.0, 1.0);snowEmitter.shadowColor   = [[UIColor whiteColor] CGColor];        //snowflake.emissionLatitude=-M_PI_2;//按照Z軸旋轉    snowEmitter.preservesDepth=YES;    CATransform3D transform = CATransform3DIdentity;    transform.m34 = -1.0/300.0f;    self.view.layer.transform=transform;    // Add everything to our backing layer below the UIContol defined in the storyboardsnowEmitter.emitterCells = [NSArray arrayWithObject:snowflake];[self.view.layer insertSublayer:snowEmitter atIndex:0];

主要是3DZ軸方向的應用,如果越靠近你的視野,則圖片更大,這個效果可以通過設定父Layer的景深來實現。

參考文檔:

Animation Types and Timing Programming Guide

Core Animation Programming Guide

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.