iOS 動畫 第八章 顯示動畫

      //CABasicAnimation
    //[self basicAnimationTest];
    
    //animationDelegate
    //[self animationDelegateTest];
    
    //clockViewAnimationTest
    //[self clockViewAnimationTest];
    
    //keyframeAnimation
    //[self keyframeAnimationTest];
    
    //CGPath
    //[self keyframeAnimationPathTest];
    
    //虛擬屬性
    //[self valueRotationTest];
    //[self virtualValueRotationTest];

    //動畫數(shù)組
    //[self animationGroupTest];
    
    //過渡
    //[self transitionTest];
    //自定義動畫
    //[self transitionSelfTest];
    
    //截圖
    //[self performTransition];
    
    //取消動畫
    //[self cancelAnimationTest];
    
    //duration repeatCount
    //[self durationAndRepeatCountTest];
    
    //repeatDuration
    //[self repeatDurationTest];
    
    //timeOffset and speed
    //[self timeOffsetAndSpeedTest];
    
    //handle animation
    //[self handleAnimationTest];

屬性動畫

//屬性動畫:作用于圖層的某個單一屬性,并指定了它的一個目標(biāo)值筐带,或者一連串將要做動畫的值。 分為兩種:基礎(chǔ)和關(guān)鍵幀

基礎(chǔ)動畫

//CABasicAnimation是CAPropertyAnimation的一個子類,而CAPropertyAnimation的父類是CAAnimation窿冯,CAAnimation同時也是Core Animation所有動畫類型的抽象基類。
//CAAnimation提供了一個計時函數(shù),一個委托(用于反饋動畫狀態(tài))以及一個removedOnCompletion确徙,用于標(biāo)識動畫是否該在結(jié)束后自動釋放(默認(rèn)YES醒串,為了防止內(nèi)存泄露)。CAAnimation同時實現(xiàn)了一些協(xié)議鄙皇,包括CAAction(允許CAAnimation的子類可以提供圖層行為)芜赌,以及CAMediaTiming
//CAPropertyAnimation : keyPath 僅可以作用于圖層本身的屬性,而且還包含了它的子成員的屬性伴逸,甚至是一些虛擬的屬性
//CABasicAnimation繼承于CAPropertyAnimation缠沈,add property id fromValue id toValue id byValue
//fromValue代表了動畫開始之前屬性的值,toValue代表了動畫結(jié)束之后的值错蝴,byValue代表了動畫執(zhí)行過程中改變的值洲愤。 只需要指定toValue或者byValue
//Type Object Type Code Example
//CGFloat NSNumber id obj = @(float);
//CGPoint NSValue id obj = [NSValue valueWithCGPoint:point);
//CGSize NSValue id obj = [NSValue valueWithCGSize:size);
//CGRect NSValue id obj = [NSValue valueWithCGRect:rect);
//CATransform3D NSValue id obj = [NSValue valueWithCATransform3D:transform);
//CGImageRef id id obj = (__bridge id)imageRef;
//CGColorRef id id obj = (__bridge id)colorRef;

- (void)basicAnimationTest {
    layerView  = [[UIView alloc] init];
    layerView.frame = CGRectMake(0, 20, 320, 320);
    [self.view addSubview:layerView];
    //add change color button
    UIButton *changeColorBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    changeColorBtn.frame = CGRectMake(50, 200, 200, 44.0);
    [changeColorBtn setTitle:@"change Color" forState:(UIControlStateNormal)];
    [changeColorBtn addTarget:self action:@selector(changeColorBasicAnimationAction2) forControlEvents:UIControlEventTouchUpInside];
    changeColorBtn.backgroundColor = [UIColor redColor];
    [layerView addSubview:changeColorBtn];
    
    //create sublayer
    colorLayer = [CALayer layer];
    colorLayer.frame = CGRectMake(50.0, 50.0, 100.0, 100.0f);
    colorLayer.backgroundColor = [UIColor blueColor].CGColor;
    //add it to our view
    [layerView.layer addSublayer:colorLayer];
}

- (void)changeColorBasicAnimationAction {
    //create a new random color
    CGFloat red = arc4random() / (CGFloat)INT_MAX;
    CGFloat green = arc4random() / (CGFloat)INT_MAX;
    CGFloat blue = arc4random() / (CGFloat)INT_MAX;
    UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
    
    //create a basic animation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"backgroundColor";
    //因為動畫并沒有改變圖層的模型,而只是呈現(xiàn), 一旦動畫結(jié)束并從圖層上移除之后顷锰,圖層就立刻恢復(fù)到之前定義的外觀狀態(tài) 從沒改變過backgroundColor屬性柬赐,所以圖層就返回到原始的顏色
    //在使用隱式動畫的時候,實際上它就是用例子中CABasicAnimation來實現(xiàn)的(回憶第七章官紫,我們在-actionForLayer:forKey:委托方法打印出來的結(jié)果就是CABasicAnimation)肛宋。
    //animation.fromValue = (__bridge id)colorLayer.backgroundColor;
    //colorLayer.backgroundColor = color.CGColor;
    
    //由于這里的圖層并不是UIView關(guān)聯(lián)的圖層,我們需要用CATransaction來禁用隱式動畫行為束世,否則默認(rèn)的圖層行為會干擾我們的顯式動畫
    CALayer *layer = colorLayer.presentationLayer ?: colorLayer;
    animation.fromValue = (__bridge id)layer.backgroundColor;
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    colorLayer.backgroundColor = color.CGColor;
    [CATransaction commit];
    
    animation.toValue = (__bridge id)color.CGColor;
    //apply animation to layer
    [colorLayer addAnimation:animation forKey:nil];
}
//避免在每次動畫時候都重復(fù)CATransaction的代碼悼吱。
- (void)applyBasicAnimation:(CABasicAnimation *)animation toLayer:(CALayer *)layer {
    //set the from value (using presentation layer if available)
    animation.fromValue = [layer.presentationLayer ?: layer valueForKeyPath:animation.keyPath];
    //update the property in advance
    //note: this approach will only work if toValue != nil
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    [layer setValue:animation.toValue forKey:animation.keyPath];
    [CATransaction commit];
    //apply animation to layer
    [layer addAnimation:animation forKey:nil];
}

- (void)changeColorBasicAnimationAction2 {
    //create a new random color
    CGFloat red = arc4random() / (CGFloat)INT_MAX;
    CGFloat green = arc4random() / (CGFloat)INT_MAX;
    CGFloat blue = arc4random() / (CGFloat)INT_MAX;
    UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
    
    //create a basic animation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"backgroundColor";
    animation.toValue = (__bridge id)color.CGColor;
    //apply animation without snap-back
    [self applyBasicAnimation:animation toLayer:colorLayer];
}

//CAAnimationDelegate
- (void)animationDelegateTest {
    layerView  = [[UIView alloc] init];
    layerView.frame = CGRectMake(0, 20, 320, 320);
    [self.view addSubview:layerView];
    //add change color button
    UIButton *changeColorBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    changeColorBtn.frame = CGRectMake(50, 200, 200, 44.0);
    [changeColorBtn setTitle:@"change Color" forState:(UIControlStateNormal)];
    [changeColorBtn addTarget:self action:@selector(changeColorAnimationDelegateAction) forControlEvents:UIControlEventTouchUpInside];
    changeColorBtn.backgroundColor = [UIColor redColor];
    [layerView addSubview:changeColorBtn];
    
    //create sublayer
    colorLayer = [CALayer layer];
    colorLayer.frame = CGRectMake(50.0, 50.0, 100.0, 100.0f);
    colorLayer.backgroundColor = [UIColor blueColor].CGColor;
    //add it to our view
    [layerView.layer addSublayer:colorLayer];

}

- (void)changeColorAnimationDelegateAction {
    //create a new random color
    CGFloat red = arc4random() / (CGFloat)INT_MAX;
    CGFloat green = arc4random() / (CGFloat)INT_MAX;
    CGFloat blue = arc4random() / (CGFloat)INT_MAX;
    UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
    //create a basic animation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"backgroundColor";
    animation.toValue = (__bridge id)color.CGColor;
    animation.delegate = self;
    //apply animation to layer
    [colorLayer addAnimation:animation forKey:nil];
}
/*
- (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag {
    //set backgroundColor property to match animation toValue
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    colorLayer.backgroundColor = (__bridge CGColorRef)anim.toValue;
    [CATransaction commit];
}
 */

//clockViewAnimation
- (void)clockViewAnimationTest {
    //adjust anchor points
    hourHand = [[UIImageView alloc] init];
    hourHand.frame = CGRectMake(100.0, 100.0f, 2.f, 60.0f);
    hourHand.backgroundColor = [UIColor redColor];
    hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
    [self.view addSubview:hourHand];
    
    minuteHand = [[UIImageView alloc] init];
    minuteHand.frame = CGRectMake(100.0, 100.0f, 2.f, 60.0f);
    minuteHand.backgroundColor = [UIColor blueColor];
    minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
    [self.view addSubview:minuteHand];
    
    secondHand = [[UIImageView alloc] init];
    secondHand.frame = CGRectMake(100.0, 100.0f, 2.f, 60.0f);
    secondHand.backgroundColor = [UIColor greenColor];
    secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
    [self.view addSubview:secondHand];
    //start timer
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tickAnimation) userInfo:nil repeats:YES];
    //set initial hand positions
    [self updateHandsAnimated:NO];
}

- (void)tickAnimation {
    [self updateHandsAnimated:YES];
}

- (void)updateHandsAnimated:(BOOL)animated {
    //convert time to hours, minutes and seconds
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSUInteger units = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
    CGFloat hourAngle = (components.hour / 12.0) * M_PI * 2.0;
    //calculate hour hand angle //calculate minute hand angle
    CGFloat minuteAngle = (components.minute / 60.0) * M_PI * 2.0;
    //calculate second hand angle
    CGFloat secondAngle = (components.second / 60.0) * M_PI * 2.0;
    //rotate hands
    [self setAngle:hourAngle forHand:hourHand animated:animated];
    [self setAngle:minuteAngle forHand:minuteHand animated:animated];
    [self setAngle:secondAngle forHand:secondHand animated:animated];
}
/*
- (void)setAngle:(CGFloat)angle forHand:(UIView *)handView animated:(BOOL)animated {
    //generate transform
    CATransform3D transform = CATransform3DMakeRotation(angle, 0, 0, 1);
    if (animated) {
        // create transform animation
        CABasicAnimation *animation = [CABasicAnimation animation];
        [self updateHandsAnimated:NO];
        animation.keyPath = @"transform";
        animation.toValue = [NSValue valueWithCATransform3D:transform];
        animation.duration = 0.5;
        animation.delegate = self;
        [animation setValue:handView forKey:@"handView"];
        [handView.layer addAnimation:animation forKey:nil];
    } else {
        //set transform directly
        handView.layer.transform = transform;
    }
}
 */
/*
- (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag {
    //set final position for hand view
    UIView *handView = [anim valueForKey:@"handView"];
    handView.layer.transform = [anim.toValue CATransform3DValue];
}
 */

關(guān)鍵幀動畫

//CAKeyframeAnimation同樣是CAPropertyAnimation的一個子類,它依然作用于單一的一個屬性良狈,但是和CABasicAnimation不一樣的是后添,它不限制于設(shè)置一個起始和結(jié)束的值,而是可以根據(jù)一連串隨意的值來做動畫。

- (void)keyframeAnimationTest {
    layerView  = [[UIView alloc] init];
    layerView.frame = CGRectMake(0, 20, 320, 320);
    [self.view addSubview:layerView];
    //add change color button
    UIButton *changeColorBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    changeColorBtn.frame = CGRectMake(50, 200, 200, 44.0);
    [changeColorBtn setTitle:@"change Color" forState:(UIControlStateNormal)];
    [changeColorBtn addTarget:self action:@selector(keyAnimationChangeColor) forControlEvents:UIControlEventTouchUpInside];
    changeColorBtn.backgroundColor = [UIColor redColor];
    [layerView addSubview:changeColorBtn];
    
    //create sublayer
    colorLayer = [CALayer layer];
    colorLayer.frame = CGRectMake(50.0, 50.0, 100.0, 100.0f);
    colorLayer.backgroundColor = [UIColor blueColor].CGColor;
    //add it to our view
    [layerView.layer addSublayer:colorLayer];
    
}
- (void)keyAnimationChangeColor {
    //create a key frame animation
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"backgroundColor";
    animation.duration = 2.0f;
    animation.values = @[
                         //為了動畫的平滑特性遇西,我們需要開始和結(jié)束的關(guān)鍵幀來匹配當(dāng)前屬性的值
                         (__bridge id)[UIColor blueColor].CGColor,//不能自動把當(dāng)前值作為第一幀
                         (__bridge id)[UIColor redColor].CGColor,
                         (__bridge id)[UIColor greenColor].CGColor,
                         (__bridge id)[UIColor blueColor].CGColor,
                         ];
    //apply animation to layer
    [colorLayer addAnimation:animation forKey:nil];
}

//CGPath
- (void)keyframeAnimationPathTest {
    containerView = [[UIView alloc] init];
    containerView.frame = CGRectMake(0.0, 0.0, 320, 320);
    containerView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:containerView];
    
    //create a path
    UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
    [bezierPath moveToPoint:CGPointMake(0, 150)];
    [bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
    //draw the path using a CAShapeLayer
    CAShapeLayer *pathLayer = [CAShapeLayer layer];
    pathLayer.path = bezierPath.CGPath;
    pathLayer.fillColor = [UIColor clearColor].CGColor;
    pathLayer.strokeColor = [UIColor redColor].CGColor;
    pathLayer.lineWidth = 3.0f;
    [containerView.layer addSublayer:pathLayer];
    
    //add the ship
    CALayer *starLayer = [CALayer layer];
    starLayer.frame = CGRectMake(0, 0, 64, 64);
    starLayer.position = CGPointMake(0, 150);
    starLayer.contents = (__bridge id)[UIImage imageNamed:@"Star"].CGImage;
    [containerView.layer addSublayer:starLayer];
    
    //create the keyframe animation
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position";
    animation.duration = 4.0;
    animation.path = bezierPath.CGPath;
    //指向曲線切線的方向
    animation.rotationMode = kCAAnimationRotateAuto;
    [starLayer addAnimation:animation forKey:nil];
}

虛擬屬性

- (void)valueRotationTest {
    containerView = [[UIView alloc] init];
    containerView.frame = CGRectMake(0.0, 0.0, 320, 320);
    containerView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:containerView];
    
    //add the ship
    CALayer *starLayer = [CALayer layer];
    starLayer.frame = CGRectMake(0, 0, 128, 128);
    starLayer.position = CGPointMake(150, 150);
    starLayer.contents = (__bridge id)[UIImage imageNamed:@"Star"].CGImage;
    [containerView.layer addSublayer:starLayer];
    
    //animate the star rotation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform";
    animation.duration = 2.0;
    //從M_PI(180度)調(diào)整到2 * M_PI(360度)馅精,然后運行程序,會發(fā)現(xiàn)這時候飛船完全不動了
    //用byValue而不是toValue, 沒有做任何旋轉(zhuǎn)粱檀,這是因為變換矩陣不能像角度值那樣疊加
    animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 0, 0, 1)];
    [starLayer addAnimation:animation forKey:nil];
}

//transform.rotation屬性有一個奇怪的問題是它其實并不存在洲敢。這是因為CATransform3D并不是一個對象,它實際上是一個結(jié)構(gòu)體茄蚯,也沒有符合KVC相關(guān)屬性压彭,transform.rotation實際上是一個CALayer用于處理動畫變換的虛擬屬性。
//當(dāng)你對他們做動畫時渗常,Core Animation自動地根據(jù)通過CAValueFunction來計算的值來更新transform屬性壮不。
//CAValueFunction用于把我們賦給虛擬的transform.rotation簡單浮點值轉(zhuǎn)換成真正的用于擺放圖層的CATransform3D矩陣值。你可以通過設(shè)置CAPropertyAnimation的valueFunction屬性來改變皱碘,于是你設(shè)置的函數(shù)將會覆蓋默認(rèn)的函數(shù)询一。

//用transform.rotation而不是transform做動畫的好處如下:
//我們可以不通過關(guān)鍵幀一步旋轉(zhuǎn)多于180度的動畫。
//可以用相對值而不是絕對值旋轉(zhuǎn)(設(shè)置byValue而不是toValue)癌椿。
//可以不用創(chuàng)建CATransform3D健蕊,而是使用一個簡單的數(shù)值來指定角度。
//不會和transform.position或者transform.scale沖突(同樣是使用關(guān)鍵路徑來做獨立的動畫屬性)踢俄。

- (void)virtualValueRotationTest {
    containerView = [[UIView alloc] init];
    containerView.frame = CGRectMake(0.0, 0.0, 320, 320);
    containerView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:containerView];
    
    //add the ship
    CALayer *starLayer = [CALayer layer];
    starLayer.frame = CGRectMake(0, 0, 128, 128);
    starLayer.position = CGPointMake(150, 150);
    starLayer.contents = (__bridge id)[UIImage imageNamed:@"Star"].CGImage;
    [containerView.layer addSublayer:starLayer];
    
    //animate the star rotation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation";
    animation.duration = 2.0;
    animation.toValue = @(M_PI *2);
    [starLayer addAnimation:animation forKey:nil];
}

動畫組

//CAAnimationGroup是另一個繼承于CAAnimation的子類缩功,它添加了一個animations數(shù)組的屬性,用來組合別的動畫都办。

- (void)animationGroupTest {
    containerView = [[UIView alloc] init];
    containerView.frame = CGRectMake(0.0, 0.0, 320, 320);
    containerView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:containerView];
    
    //create a path
    UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
    [bezierPath moveToPoint:CGPointMake(0, 150)];
    [bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
    //draw the path using a CAShapeLayer
    CAShapeLayer *pathLayer = [CAShapeLayer layer];
    pathLayer.path = bezierPath.CGPath;
    pathLayer.fillColor = [UIColor clearColor].CGColor;
    pathLayer.strokeColor = [UIColor redColor].CGColor;
    pathLayer.lineWidth = 3.0f;
    [containerView.layer addSublayer:pathLayer];
    
    //add a colored layer
    colorLayer = [CALayer layer];
    colorLayer.frame = CGRectMake(0, 0, 64, 64);
    colorLayer.backgroundColor = [UIColor greenColor].CGColor;
    [containerView.layer addSublayer:colorLayer];
    
    //create the position animation
    CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];
    animation1.keyPath = @"position";
    animation1.path = bezierPath.CGPath;
    animation1.rotationMode = kCAAnimationRotateAuto;
    //create the color animation
    CABasicAnimation *animation2 = [CABasicAnimation animation];
    animation2.keyPath = @"backgroundColor";
    animation2.toValue = (__bridge id)[UIColor redColor].CGColor;
    //create the animation group
    CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
    groupAnimation.animations = @[animation1, animation2];
    groupAnimation.duration = 4.0;
    //add the animation to the color layer
    [colorLayer addAnimation:groupAnimation forKey:nil];
}

過渡

//CATransition:CAAnimation的子類,有一個type和subtype來標(biāo)識變換效果嫡锌。
//type屬性是一個NSString類型
//kCATransitionFade:平滑的淡入淡出效果
//kCATransitionMoveIn:從頂部滑動進入
//kCATransitionPush:它創(chuàng)建了一個新的圖層,從邊緣的一側(cè)滑動進來脆丁,把舊圖層從另一側(cè)推出去的效果世舰。
//kCATransitionReveal:把原始的圖層滑動出去來顯示新的外觀动雹,而不是把新的圖層滑動進入

//subtype
//kCATransitionFromRight
//kCATransitionFromLeft
//kCATransitionFromTop
//kCATransitionFromBottom

- (void)transitionTest {
    imageView = [[UIImageView alloc] init];
    imageView.frame = CGRectMake(0, 20, 320, 320);
    imageView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:imageView];
    
    UIButton *btnSwitchImage = [UIButton buttonWithType:UIButtonTypeCustom];
    btnSwitchImage.frame = CGRectMake(20, 350, 200, 44);
    btnSwitchImage.backgroundColor = [UIColor blueColor];
    [btnSwitchImage setTitle:@"Switch Image" forState:UIControlStateNormal];
    [btnSwitchImage addTarget:self action:@selector(switchImageAction) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btnSwitchImage];
    
    //set up images
    images = @[
               [UIImage imageNamed:@"Meal"],
               [UIImage imageNamed:@"Star"],
               [UIImage imageNamed:@"Meal"],
               [UIImage imageNamed:@"Star"]
               ];
}

- (void)switchImageAction {
    //set up crossfade transition
    CATransition *transition = [CATransition animation];
    transition.type = kCATransitionReveal;
    //apply transition to imageView backing layer
    [imageView.layer addAnimation:transition forKey:nil];
    
    //cycle to next image
    UIImage *currentImage = imageView.image;
    NSUInteger index = [images indexOfObject:currentImage];
    index = (index + 1) % [images count];
    imageView.image = images[index];
}

隱式過渡

//當(dāng)設(shè)置了CALayer的content屬性的時候槽卫,CATransition的確是默認(rèn)的行為
//對于視圖關(guān)聯(lián)的圖層,或者是其他隱式動畫的行為胰蝠,這個特性依然是被禁用的歼培,但是對于你自己創(chuàng)建的圖層,這意味著對圖層contents圖片做的改動都會自動附上淡入淡出的動畫茸塞。

//對圖層樹的動畫
//to appdelegate first and second viewController

//自定義動畫
//更奇怪的是蘋果通過UIView +transitionFromView:toView:duration:options:completion:和+transitionWithView:duration:options:animations:方法提供了Core Animation的過渡特性躲庄。但是這里的可用的過渡選項和CATransition的type屬性提供的常量完全不同。
//UIView過渡方法中options參數(shù)可以由如下常量指定:
//UIViewAnimationOptionTransitionFlipFromLeft
//UIViewAnimationOptionTransitionFlipFromRight
//UIViewAnimationOptionTransitionCurlUp
//UIViewAnimationOptionTransitionCurlDown
//UIViewAnimationOptionTransitionCrossDissolve
//UIViewAnimationOptionTransitionFlipFromTop
//UIViewAnimationOptionTransitionFlipFromBottom

- (void)transitionSelfTest {
    imageView = [[UIImageView alloc] init];
    imageView.frame = CGRectMake(0, 20, 320, 320);
    imageView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:imageView];
    
    UIButton *btnSwitchImage = [UIButton buttonWithType:UIButtonTypeCustom];
    btnSwitchImage.frame = CGRectMake(20, 350, 200, 44);
    btnSwitchImage.backgroundColor = [UIColor blueColor];
    [btnSwitchImage setTitle:@"Switch Image" forState:UIControlStateNormal];
    [btnSwitchImage addTarget:self action:@selector(selfSwitchImageAction) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btnSwitchImage];
    
    //set up images
    images = @[
               [UIImage imageNamed:@"Meal"],
               [UIImage imageNamed:@"Star"],
               [UIImage imageNamed:@"Meal"],
               [UIImage imageNamed:@"Star"]
               ];
}

- (void)selfSwitchImageAction {
    [UIView transitionWithView:imageView
                      duration:1.0
                       options:UIViewAnimationOptionTransitionFlipFromLeft
                    animations:^{
                        //cycle to next image
                        UIImage *currentImage = imageView.image;
                        NSUInteger index = [images indexOfObject:currentImage];
                        index = (index + 1) % [images count];
                        imageView.image = images[index];
                    }
                    completion:nil];
}

//對圖層做截圖還是很簡單的钾虐。CALayer有一個-renderInContext:方法噪窘,可以通過把它繪制到Core Graphics的上下文中捕獲當(dāng)前內(nèi)容的圖片,然后在另外的視圖中顯示出來效扫。
//為了讓事情更簡單倔监,我們用UIView -animateWithDuration:completion:方法來實現(xiàn)直砂。雖然用CABasicAnimation可以達到同樣的效果,但是那樣的話我們就需要對圖層的變換和不透明屬性創(chuàng)建單獨的動畫浩习,然后當(dāng)動畫結(jié)束的是哦戶在CAAnimationDelegate中把coverView從屏幕中移除静暂。
//用renderInContext:創(chuàng)建自定義過渡效果

- (void)performTransition {
    
    //preserve the current view snapshot
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, YES, 0.0);
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *coverImage = UIGraphicsGetImageFromCurrentImageContext();
    //insert snapshot view in front of this one
    UIView *coverView = [[UIImageView alloc] initWithImage:coverImage];
    coverView.frame = self.view.bounds;
    [self.view addSubview:coverView];
    //update the view (we'll simply randomize the layer background color)
    CGFloat red = arc4random() / (CGFloat)INT_MAX;
    CGFloat green = arc4random() / (CGFloat)INT_MAX;
    CGFloat blue = arc4random() / (CGFloat)INT_MAX;
    self.view.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
    //perform animation (anything you like)
    [UIView animateWithDuration:1.0 animations:^{
        //scale, rotate and fade the view
        CGAffineTransform transform = CGAffineTransformMakeScale(0.01, 0.01);
        transform = CGAffineTransformRotate(transform, M_PI_2);
        coverView.transform = transform;
        coverView.alpha = 0.0;
        
    } completion:^(BOOL finished) {
        //remove the cover view now we're finished with it
        [coverView removeFromSuperview];
    }];
}

在動畫過程中取消動畫

//你可以用-addAnimation:forKey:方法中的key參數(shù)來在添加動畫之后檢索一個動畫,使用如下方法:
//- (CAAnimation *)animationForKey:(NSString *)key;
//- (void)removeAnimationForKey:(NSString *)key;
//- (void)removeAllAnimations;
//動畫在結(jié)束之后被自動移除谱秽,除非設(shè)置removedOnCompletion為NO洽蛀,如果你設(shè)置動畫在結(jié)束之后不被自動移除,那么當(dāng)它不需要的時候你要手動移除它疟赊;否則它會一直存在于內(nèi)存中郊供,直到圖層被銷毀。

- (void)cancelAnimationTest {
    containerView = [[UIView alloc] init];
    containerView.frame = CGRectMake(0.0, 20.0, 320, 320);
    containerView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:containerView];
    
    UIButton *startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    startBtn.frame = CGRectMake(0.0, 400, 100, 44.0f);
    [startBtn setTitle:@"Star" forState:UIControlStateNormal];
    [startBtn addTarget:self action:@selector(startAction) forControlEvents:UIControlEventTouchUpInside];
    [startBtn setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview:startBtn];
    
    UIButton *stopBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    stopBtn.frame = CGRectMake(120.0, 400, 100, 44.0f);
    [stopBtn setTitle:@"Stop" forState:UIControlStateNormal];
    [stopBtn addTarget:self action:@selector(stopAction) forControlEvents:UIControlEventTouchUpInside];
    [stopBtn setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview:stopBtn];

    
    //add the star
    starLayer = [CALayer layer];
    starLayer.frame = CGRectMake(0, 0, 128, 128);
    starLayer.position = CGPointMake(150, 150);
    starLayer.contents = (__bridge id)[UIImage imageNamed:@"Star"].CGImage;
    [containerView.layer addSublayer:starLayer];
}

- (void)startAction {
    //animate the ship rotation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation";
    animation.duration = 2.0;
    animation.byValue = @(M_PI * 2);
    animation.delegate = self;
    [starLayer addAnimation:animation forKey:@"rotateAnimation"];
}

- (void)stopAction {
    [starLayer removeAnimationForKey:@"rotateAnimation"];
}
/*
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    //log that the animation stopped
    NSLog(@"The animation stopped (finished:%@", flag? @"Yes":@"No");
}
 */

pragma mark -- 圖層時間

//CAMediaTiming協(xié)議
//CAMediaTiming協(xié)議定義了在一段動畫內(nèi)用來控制逝去時間的屬性的集合听绳,CALayer和CAAnimation都實現(xiàn)了這個協(xié)議颂碘,所以時間可以被任意基于一個圖層或者一段動畫的類控制。

//持續(xù)和重復(fù)
//duration是一個CFTimeInterval的類型(類似于NSTimeInterval的一種雙精度浮點類型)椅挣,對將要進行的動畫的一次迭代指定了時間头岔。
//CAMediaTiming另外還有一個屬性叫做repeatCount,代表動畫重復(fù)的迭代次數(shù)鼠证。如果duration是2峡竣,repeatCount設(shè)為3.5(三個半迭代),那么完整的動畫時長將是7秒量九。
//duration和repeatCount默認(rèn)都是0,這里的0僅僅代表了“默認(rèn)”适掰,也就是0.25秒和1次

- (void)durationAndRepeatCountTest {
    containerView = [[UIView alloc] init];
    containerView.frame = CGRectMake(0.0, 20.0, 320, 320);
    containerView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:containerView];
    
    startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    startBtn.frame = CGRectMake(0.0, 400, 100, 44.0f);
    [startBtn setTitle:@"Star" forState:UIControlStateNormal];
    [startBtn addTarget:self action:@selector(durationStartAction) forControlEvents:UIControlEventTouchUpInside];
    [startBtn setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview:startBtn];
    
    //add the star
    starLayer = [CALayer layer];
    starLayer.frame = CGRectMake(0, 0, 128, 128);
    starLayer.position = CGPointMake(150, 150);
    starLayer.contents = (__bridge id)[UIImage imageNamed:@"Star"].CGImage;
    [containerView.layer addSublayer:starLayer];
}

- (void)setControlsEnabled:(BOOL)enbled {
    startBtn.enabled = enbled;
    startBtn.alpha = enbled? 1.0f:0.25;
}

- (void)durationStartAction {
    CFTimeInterval duration = 3.0f;
    float repeatCount = 2.5;
    //animate the star rotation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation";
    animation.duration = duration;
    animation.repeatCount = repeatCount;
    animation.byValue = @(M_PI * 2);
    animation.delegate = self;
    [starLayer addAnimation:animation forKey:@"rotateAnimation"];
    //disable controls
    [self setControlsEnabled:NO];
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    [self setControlsEnabled:YES];
}

//repeatDuration屬性:它讓動畫重復(fù)一個指定的時間,而不是指定次數(shù)荠列。
//autoreverses的屬性:(BOOL類型)在每次間隔交替循環(huán)過程中自動回放
//把repeatDuration設(shè)置為INFINITY类浪,于是動畫無限循環(huán)播放,設(shè)置repeatCount為INFINITY也有同樣的效果

- (void)repeatDurationTest {
    containerView = [[UIView alloc] init];
    containerView.frame = CGRectMake(0.0, 20.0, 320, 320);
    containerView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:containerView];
    
    //add the door
    CALayer *doorLayer = [CALayer layer];
    doorLayer.frame = CGRectMake(0, 0, 128, 256);
    doorLayer.position = CGPointMake(150-64, 150);
    doorLayer.anchorPoint = CGPointMake(0, 0.5);
    doorLayer.contents = (__bridge id)[UIImage imageNamed:@"Star"].CGImage;
    [containerView.layer addSublayer:doorLayer];
    //apply perspective transform
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = -1.0 / 500.0;
    containerView.layer.sublayerTransform = perspective;
    //apply swinging animation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation.y";
    animation.toValue = @(-M_PI_2);
    animation.duration = 2.0;
    animation.repeatDuration = INFINITY;
    animation.autoreverses = YES;
    [doorLayer addAnimation:animation forKey:nil];
}

相對時間

//beginTime指定了動畫開始之前的的延遲時間
//speed是一個時間的倍數(shù)肌似,默認(rèn)1.0费就,減少它會減慢圖層/動畫的時間,增加它會加快速度川队。
//timeOffset:增加timeOffset只是讓動畫快進到某一點;對于一個持續(xù)1秒的動畫來說力细,設(shè)置timeOffset為0.5意味著動畫將從一半的地方開始
//timeOffset并不受speed的影響,。所以如果你把speed設(shè)為2.0固额,把timeOffset設(shè)置為0.5眠蚂,那么你的動畫將從動畫最后結(jié)束的地方開始,因為1秒的動畫實際上被縮短到了0.5秒斗躏。然而即使使用了timeOffset讓動畫從結(jié)束的地方開始逝慧,它仍然播放了一個完整的時長,這個動畫僅僅是循環(huán)了一圈,然后從頭開始播放笛臣。

- (void)timeOffsetAndSpeedTest {
    containerView = [[UIView alloc] init];
    containerView.frame = CGRectMake(0.0, 20.0, 320, 320);
    containerView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:containerView];
    
    speedLabel = [[UILabel alloc] init];
    speedLabel.frame = CGRectMake(0.0, 400.0, 100, 40.0f);
    speedLabel.backgroundColor = [UIColor grayColor];
    [self.view addSubview:speedLabel];
    
    speedSlider = [[UISlider alloc] init];
    speedSlider.frame = CGRectMake(0.0, 450, 320, 40);
    speedSlider.backgroundColor = [UIColor purpleColor];
    [speedSlider addTarget:self action:@selector(updateSliders) forControlEvents:UIControlEventValueChanged];

    [self.view addSubview:speedSlider];
    
    
    timeOffsetLabel = [[UILabel alloc] init];
    timeOffsetLabel.frame = CGRectMake(120, 400.0, 100, 40.0f);
    timeOffsetLabel.backgroundColor = [UIColor grayColor];
    [self.view addSubview:timeOffsetLabel];
    
    timeOffsetSlider = [[UISlider alloc] init];
    timeOffsetSlider.frame = CGRectMake(0.0, 500, 320, 40);
    timeOffsetSlider.backgroundColor = [UIColor purpleColor];
    [timeOffsetSlider addTarget:self action:@selector(updateSliders) forControlEvents:UIControlEventValueChanged];
    [self.view addSubview:timeOffsetSlider];
    
    startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    startBtn.frame = CGRectMake(0.0, 550, 100, 44.0f);
    [startBtn setTitle:@"Star" forState:UIControlStateNormal];
    [startBtn addTarget:self action:@selector(playAction) forControlEvents:UIControlEventTouchUpInside];
    [startBtn setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview:startBtn];
    
    //create a path
    bezierPath = [[UIBezierPath alloc] init];
    [bezierPath moveToPoint:CGPointMake(0, 150)];
    [bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
    //draw the path using a cashapeLayer
    CAShapeLayer *pathLayer = [CAShapeLayer layer];
    pathLayer.path = bezierPath.CGPath;
    pathLayer.fillColor = [UIColor clearColor].CGColor;
    pathLayer.strokeColor = [UIColor redColor].CGColor;
    pathLayer.lineWidth = 3.0f;
    [containerView.layer addSublayer:pathLayer];
    
    //add the star
    starLayer = [CALayer layer];
    starLayer.frame = CGRectMake(0, 0, 64, 64);
    starLayer.position = CGPointMake(0, 150);
    starLayer.contents = (__bridge id)[UIImage imageNamed:@"Star"].CGImage;
    [containerView.layer addSublayer:starLayer];
    //set initial values
    [self updateSliders];
}

- (void)updateSliders {
    CFTimeInterval timeOffset = timeOffsetSlider.value;
    timeOffsetLabel.text = [NSString stringWithFormat:@"%f", timeOffset];
    float speed = speedSlider.value;
    speedLabel.text = [NSString stringWithFormat:@"%f", speed];
}

- (void)playAction {
    //create the keyframe animation
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position";
    animation.timeOffset = timeOffsetSlider.value;
    animation.speed = speedSlider.value;
    animation.duration = 1.0;
    animation.path = bezierPath.CGPath;
    animation.rotationMode = kCAAnimationRotateAuto;
    animation.removedOnCompletion = NO;
    [starLayer addAnimation:animation forKey:@"slide"];
}

fillMode

//一種可能是屬性和動畫沒被添加之前保持一致栅干,也就是在模型圖層定義的值(見第七章“隱式動畫”,模型圖層和呈現(xiàn)圖層的解釋)捐祠。
//另一種可能是保持動畫開始之前那一幀碱鳞,或者動畫結(jié)束之后的那一幀。這就是所謂的填充踱蛀,因為動畫開始和結(jié)束的值用來填充開始之前和結(jié)束之后的時間窿给。
//需要把removeOnCompletion設(shè)置為NO,另外需要給動畫添加一個非空的鍵率拒,于是可以在不需要動畫的時候把它從圖層上移除崩泡。
//fillMode:NSString類型
//kCAFillModeForwards
//kCAFillModeBackwards
//kCAFillModeBoth
//kCAFillModeRemoved 默認(rèn)

層級關(guān)系時間

//對圖層調(diào)整時間將會影響到它本身和子圖層的動畫,但不會影響到父圖層猬膨。另一個相似點是所有的動畫都被按照層級組合(使用CAAnimationGroup實例)
//對CALayer或者CAGroupAnimation調(diào)整duration和repeatCount/repeatDuration屬性并不會影響到子動畫角撞。但是beginTime,timeOffset和speed屬性將會影響到子動畫勃痴。

全局時間和本地時間

//全局時間
//CACurrentMediaTime函數(shù)來訪問馬赫時間:
//CFTimeInterval time = CACurrentMediaTime();//它返回了設(shè)備自從上次啟動后的秒數(shù)谒所,并不是你所關(guān)心的,它真實的作用在于對動畫的時間測量提供了一個相對值。注意當(dāng)設(shè)備休眠的時候馬赫時間會暫停沛申,也就是所有的CAAnimations(基于馬赫時間)同樣也會暫停劣领。
//每個CALayer和CAAnimation實例都有自己本地時間的概念,是根據(jù)父圖層/動畫層級關(guān)系中的beginTime铁材,timeOffset和speed屬性計算尖淘。就和轉(zhuǎn)換不同圖層之間坐標(biāo)關(guān)系一樣,CALayer同樣也提供了方法來轉(zhuǎn)換不同圖層之間的本地時間著觉。如下:
//- (CFTimeInterval)convertTime:(CFTimeInterval)t fromLayer:(CALayer *)l;
//- (CFTimeInterval)convertTime:(CFTimeInterval)t toLayer:(CALayer *)l;
//當(dāng)用來同步不同圖層之間有不同的speed村生,timeOffset和beginTime的動畫,這些方法會很有用饼丘。

暫停趁桃,倒回和快進

//可以利用CAMediaTiming來暫停圖層本身
//如果把圖層的speed設(shè)置成0,它會暫停任何添加到圖層上的動畫葬毫。類似的镇辉,設(shè)置speed大于1.0將會快進屡穗,設(shè)置成一個負(fù)值將會倒回動畫贴捡。
//self.window.layer.speed = 100;

手動動畫

//timeOffset一個很有用的功能在于你可以它可以讓你手動控制動畫進程,通過設(shè)置speed為0村砂,可以禁用動畫的自動播放烂斋,然后來使用timeOffset來來回顯示動畫序列。這可以使得運用手勢來手動控制動畫變得很簡單。

- (void)handleAnimationTest {
    containerView = [[UIView alloc] init];
    containerView.frame = CGRectMake(0.0, 20.0, 320, 320);
    containerView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:containerView];
    
    //add the door
    starLayer = [CALayer layer];
    starLayer.frame = CGRectMake(0, 0, 128, 256);
    starLayer.position = CGPointMake(150-64, 150);
    starLayer.anchorPoint = CGPointMake(0, 0.5);
    starLayer.contents = (__bridge id)[UIImage imageNamed:@"Star"].CGImage;
    [containerView.layer addSublayer:starLayer];
    
    //apply perspective transform
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = -1.0 / 500.0;
    containerView.layer.sublayerTransform = perspective;
    
    //add pan gesture recognizer to handle swipes
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] init];
    [pan addTarget:self action:@selector(pan:)];
    [self.view addGestureRecognizer:pan];
    
    //pause all layer animations
    starLayer.speed = 0.0;
    //apply swinging animation (which won't play because layer is paused)
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation.y";
    animation.toValue = @(-M_PI_2);
    animation.duration = 2.0;
    animation.repeatDuration = INFINITY;
    animation.autoreverses = YES;
    [starLayer addAnimation:animation forKey:nil];
}

- (void)pan:(UIPanGestureRecognizer *)pan {
    //get horizontal component of pan gesture
    CGFloat x = [pan translationInView:self.view].x;
    //conver from points to animation duration //using a reasonable scale factor
    x /= 200.0f;
    //update timeOffset and clamp result
    CFTimeInterval timeOffset = starLayer.timeOffset;
    timeOffset = MIN(0.999, MAX(0.0, timeOffset - x));
    starLayer.timeOffset = timeOffset;
    //reset pan gesture
    [pan setTranslation:CGPointZero inView:self.view];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末汛骂,一起剝皮案震驚了整個濱河市罕模,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帘瞭,老刑警劉巖淑掌,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蝶念,居然都是意外死亡抛腕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門媒殉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來担敌,“玉大人,你說我怎么就攤上這事廷蓉∪猓” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵桃犬,是天一觀的道長刹悴。 經(jīng)常有香客問我,道長攒暇,這世上最難降的妖魔是什么颂跨? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮扯饶,結(jié)果婚禮上恒削,老公的妹妹穿的比我還像新娘。我一直安慰自己尾序,他們只是感情好钓丰,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著每币,像睡著了一般携丁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上兰怠,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天梦鉴,我揣著相機與錄音,去河邊找鬼揭保。 笑死肥橙,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秸侣。 我是一名探鬼主播存筏,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼崇渗,長吁一口氣:“原來是場噩夢啊……” “哼突照!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挪挤,失蹤者是張志新(化名)和其女友劉穎涩僻,沒想到半個月后捏肢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚣常,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年垂涯,在試婚紗的時候發(fā)現(xiàn)自己被綠了汁掠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡集币,死狀恐怖考阱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鞠苟,我是刑警寧澤乞榨,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站当娱,受9級特大地震影響吃既,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跨细,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一鹦倚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冀惭,春花似錦震叙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至戚丸,卻和暖如春划址,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背限府。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工夺颤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胁勺。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓世澜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姻几。 傳聞我的和親對象是個殘疾皇子宜狐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜蛇捌,今天將帶大家一窺ios動畫全貌抚恒。在這里你可以看...
    每天刷兩次牙閱讀 8,495評論 6 30
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜络拌,今天將帶大家一窺iOS動畫全貌俭驮。在這里你可以看...
    F麥子閱讀 5,113評論 5 13
  • 在iOS實際開發(fā)中常用的動畫無非是以下四種:UIView動畫,核心動畫春贸,幀動畫混萝,自定義轉(zhuǎn)場動畫。 1.UIView...
    請叫我周小帥閱讀 3,101評論 1 23
  • 書寫的很好萍恕,翻譯的也棒逸嘀!感謝譯者,感謝感謝允粤! iOS-Core-Animation-Advanced-Techni...
    錢噓噓閱讀 2,298評論 0 6
  • Core Animation Core Animation崭倘,中文翻譯為核心動畫,它是一組非常強大的動畫處理API类垫,...
    45b645c5912e閱讀 3,032評論 0 21