你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS CoreAnimation的使用

iOS CoreAnimation的使用

編輯:IOS開發綜合

前言

最近剛好需要用到一些動畫效果,所以對CoreAnimation 進行了一些研究,在使用過程中,也有產生一些疑問,在此和大家分享。

本文主要是展示對CoreAnimation 的快速使用,多種動畫的集合,每一個動畫放在一個獨立的VC中,清晰的代碼,也有購物車動畫,轉場動畫,彈簧動畫等等。

CoreAnimation 使用

基礎類的熟悉

CAAnimation:核心動畫的基類,由屬性timingFunction控制動畫運行的速度變化,由duration 控制動畫持續時間。

 

CAPropertyAnimation:屬性動畫的基類。

 

CAAnimationGroup:動畫組,可以將多個動畫組合,並行一起執行的一個類。

 

CATransition:轉場動畫,在切換一些視圖,可以產生較炫麗的動畫效果。

 

CABasicAnimation:基礎動畫,屬性動畫,可以直接使用,一般是較簡單的動畫。

 

CAKeyframeAnimation:關鍵幀動畫,屬性動畫,可以直接使用,一般通過描述Point 來進行動畫的操作,可以有多個不同的狀態變化。

 

 

創建基礎動畫BaseAnimationVC

 

 

接下來我們創建一個AnimationSummaryDemo 動畫集合的 Demo,基礎的 VC 使用 Storyboard , Demo 有簡單移動、旋轉、縮放、多點軌跡移動、曲線移動、組合動畫、彈簧動畫、轉場動畫,並且大部分動畫,我們用一個簡單的矩形作為直觀的動畫操作。

 

既然這麼多個動畫都有共同的操作 UI , 所以我們創建一個動畫基類 WBBaseAnimationVC, 將 UI 放在一起, 在子類中,只展示動畫的代碼。

 

 

#import "ViewController.h"

@protocol WBBaseAnimationDelegate 

- (void)starAnimation;

- (void)removeAnimation;

@end

@interface WBBaseAnimationVC : UIViewController 

@property (nonatomic, strong) UIView *animationView;
@property (nonatomic, readonly) UIButton *starAnimationButton;
@property (nonatomic, readonly) UIButton *removeAnimationButton;

@end

 

 

 

這裡是貼上 頭文件部分,具體看 Demo 。

 

 

 

簡單移動

創建一個WBSimpleMovingVC ,繼承於WBBaseAnimationVC 。 .m 如下

 

 

#pragma mark - WBBaseAnimationDelegate methods

- (void)starAnimation {
    
    //創建基礎動畫
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    //動畫持續時間
    animation.duration = 2.0f;
    //重復次數
    animation.repeatCount = HUGE_VALF;
    //是否執行逆動畫
    animation.autoreverses = YES;
    //動畫的速度變化
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    
    //動畫的起始位置(當前)
    animation.fromValue = [NSValue valueWithCGPoint:self.animationView.layer.position];
    //動畫的終點位置
    animation.toValue = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH - self.animationView.width / 2.0, SCREEN_HEIGHT - self.animationView.height / 2.0)];
    
    [self.animationView.layer addAnimation:animation forKey:@"position"];
}

- (void)removeAnimation {
    [self.animationView.layer removeAllAnimations];
}

 

 

 

\

 

 

 

旋轉動畫

創建WBRotatingVC ,繼承於WBBaseAnimationVC , .m 如下

 

 

#import "WBRotatingVC.h"

typedef NS_ENUM(NSUInteger, WBRotatingAxis) {
    
    WBRotatingAxisNone ,
    WBRotatingAxisX ,
    WBRotatingAxisY ,
    WBRotatingAxisZ
};

@interface WBRotatingVC ()

@end

@implementation WBRotatingVC

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *axisX = [UIButton buttonWithType:UIButtonTypeCustom];
    axisX.titleLabel.font = [UIFont systemFontOfSize:15];
    [axisX setTitle:@"X 軸旋轉" forState:UIControlStateNormal];
    [axisX setTitleColor:[UIColor colorWithRed:0.307 green:0.397 blue:1.000 alpha:1.000] forState:UIControlStateNormal];
    [axisX setBackgroundColor:[UIColor colorWithWhite:0.814 alpha:1.000]];
    [axisX addTarget:self action:@selector(rotatingWithAxisX:) forControlEvents:UIControlEventTouchUpInside];
    
    UIButton *axisY = [UIButton buttonWithType:UIButtonTypeCustom];
    axisY.titleLabel.font = [UIFont systemFontOfSize:15];
    [axisY setTitle:@"Y 軸旋轉" forState:UIControlStateNormal];
    [axisY setTitleColor:[UIColor colorWithRed:0.307 green:0.397 blue:1.000 alpha:1.000] forState:UIControlStateNormal];
    [axisY setBackgroundColor:[UIColor colorWithWhite:0.814 alpha:1.000]];
    [axisY addTarget:self action:@selector(rotatingWithAxisY:) forControlEvents:UIControlEventTouchUpInside];
    
    UIButton *axisZ = [UIButton buttonWithType:UIButtonTypeCustom];
    axisZ.titleLabel.font = [UIFont systemFontOfSize:15];
    [axisZ setTitle:@"Z 軸旋轉" forState:UIControlStateNormal];
    [axisZ setTitleColor:[UIColor colorWithRed:0.307 green:0.397 blue:1.000 alpha:1.000] forState:UIControlStateNormal];
    [axisZ setBackgroundColor:[UIColor colorWithWhite:0.814 alpha:1.000]];
    [axisZ addTarget:self action:@selector(rotatingWithAxisZ:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:axisX];
    [self.view addSubview:axisY];
    [self.view addSubview:axisZ];
    
    [axisX mas_makeConstraints:^(MASConstraintMaker *make) {
        make.trailing.equalTo(@0);
        make.top.equalTo(@129);
        make.width.equalTo(@80);
        make.height.equalTo(@40);
    }];
    
    [axisY mas_makeConstraints:^(MASConstraintMaker *make) {
        make.trailing.equalTo(@0);
        make.top.equalTo(axisX.mas_bottom).offset(10);
        make.width.equalTo(@80);
        make.height.equalTo(@40);
    }];
    
    [axisZ mas_makeConstraints:^(MASConstraintMaker *make) {
        make.trailing.equalTo(@0);
        make.top.equalTo(axisY.mas_bottom).offset(10);
        make.width.equalTo(@80);
        make.height.equalTo(@40);
    }];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Private methods

- (IBAction)rotatingWithAxisX:(id)sender {
    [self rotatingAnimationWithRotatingAxis:WBRotatingAxisX];
}

- (IBAction)rotatingWithAxisY:(id)sender {
    [self rotatingAnimationWithRotatingAxis:WBRotatingAxisY];
}

- (IBAction)rotatingWithAxisZ:(id)sender {
    [self rotatingAnimationWithRotatingAxis:WBRotatingAxisZ];
}

- (void)rotatingAnimationWithRotatingAxis:(WBRotatingAxis)rotatingAxis {

    [self removeAnimation];
    
    CABasicAnimation *animation;
    if (rotatingAxis == WBRotatingAxisNone) {
        animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];      //平面沿著中心點旋轉
    } else if (rotatingAxis == WBRotatingAxisX) {
        animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];    //沿 X
    } else if (rotatingAxis == WBRotatingAxisY) {
        animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];    //沿 Y
    } else if (rotatingAxis == WBRotatingAxisZ) {
        animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];    //沿 Z
    }
    
    //起始
    animation.fromValue = [NSNumber numberWithFloat:0];
    //旋轉角度
    animation.toValue = [NSNumber numberWithFloat:M_PI * 6];
    //持續時間
    animation.duration = 2.0f;
    //動畫的速度變化
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    //重復次數
    animation.repeatCount = HUGE_VALF;
    
    [self.animationView.layer addAnimation:animation forKey:@"rotationAnimation"];
}

#pragma mark - WBBaseAnimationDelegate methods

- (void)starAnimation {
    [self rotatingAnimationWithRotatingAxis:WBRotatingAxisNone];
}

- (void)removeAnimation {
    [self.animationView.layer removeAllAnimations];
}

@end

旋轉還有分為 x ,y ,z 軸旋轉。

 

 

 

 

\

 

 

 

 

 

縮放動畫

 

創建WBZoomingVC , 繼承於WBBaseAnimationVC , .m 如下

 

 

#pragma mark - WBBaseAnimationDelegate methods

- (void)starAnimation {
    
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    animation.duration = 1.5f;
    animation.repeatCount = HUGE_VALF;
    animation.autoreverses = YES;           
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    
    //起始倍率
    animation.fromValue = [NSNumber numberWithFloat:1.0];
    //結束時倍率
    animation.toValue = [NSNumber numberWithFloat:2.0];
    
    [self.animationView.layer addAnimation:animation forKey:@"scaleAnimation"];
}

- (void)removeAnimation {
    [self.animationView.layer removeAllAnimations];
}


 

 

 

\

 

 

 

 

 

軌跡移動

 

創建WBTrajectoryMovingVC ,繼承於WBBaseAnimationVC , .m 如下

 

 

#pragma mark - WBBaseAnimationDelegate methods

- (void)starAnimation {
    
    //創建BezierPath 對象
    UIBezierPath *path = [UIBezierPath bezierPath];
    
    //設定運行的起點
    [path moveToPoint:self.animationView.layer.position];
    //添加運動的軌跡直線點
    [path addLineToPoint:CGPointMake(SCREEN_WIDTH - self.animationView.width / 2.0, SCREEN_HEIGHT / 2.0)];
    [path addLineToPoint:CGPointMake(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT - self.animationView.width / 2.0)];
    [path addLineToPoint:CGPointMake(self.animationView.width / 2.0, SCREEN_HEIGHT / 2.0)];
    [path addLineToPoint:CGPointMake(SCREEN_WIDTH / 2.0, 64 + self.animationView.width / 2.0)];
    
    [path closePath];
    
    //創建關鍵幀動畫
    CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    pathAnimation.path = path.CGPath;           //將路徑給予動畫
    pathAnimation.duration = 8.0;               //持續時間
    pathAnimation.repeatCount = HUGE_VALF;      // 重復次數
    //    pathAnimation.autoreverses = YES;           // 是否逆動畫
    
    [self.animationView.layer addAnimation:pathAnimation forKey:@"pathAnimation"];
}

- (void)removeAnimation {
    [self.animationView.layer removeAllAnimations];
}

 

 

 

\

 

 

 

曲線運動

 

創建WBCurveMovingVC ,繼承於WBBaseAnimationVC , .m 如下

 

 

#pragma mark - WBBaseAnimationDelegate methods

- (void)starAnimation {
    
    //創建BezierPath 對象
    UIBezierPath *path = [UIBezierPath bezierPath];
    
    //設定運行的起點
    [path moveToPoint:self.animationView.layer.position];
    
    //添加軌跡點
    // addQuadCurveToPoint 和 addCurveToPoint 都是曲線方法, 區別在於參數,addCurveToPoint 可以有兩個基准點 controlPoint 作為劃線的依據
    [path addQuadCurveToPoint:CGPointMake(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT * 0.75) controlPoint:CGPointMake(SCREEN_WIDTH, SCREEN_HEIGHT * 0.625)];
    [path addQuadCurveToPoint:CGPointMake(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT - self.animationView.height / 2.0) controlPoint:CGPointMake(0, SCREEN_HEIGHT * 0.875)];
    [path addQuadCurveToPoint:CGPointMake(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT * 0.75) controlPoint:CGPointMake(SCREEN_WIDTH, SCREEN_HEIGHT * 0.875)];
    [path addQuadCurveToPoint:CGPointMake(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT / 2.0) controlPoint:CGPointMake(0, SCREEN_HEIGHT * 0.625)];
    
    // 關鍵幀動畫
    CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    keyFrameAnimation.path = path.CGPath;
    keyFrameAnimation.duration = 4.0f;
    keyFrameAnimation.repeatCount = HUGE_VALF;
    
    [self.animationView.layer addAnimation:keyFrameAnimation forKey:@"pathAnimation"];
}

- (void)removeAnimation {
    [self.animationView.layer removeAllAnimations];
}

 

 

\

 

 

 

組合運動

 

創建WBCombinationOneVC ,繼承於WBBaseAnimationVC , .m 如下

 

 

#import "WBCombinationOneVC.h"

@interface WBCombinationOneVC ()

@end

@implementation WBCombinationOneVC

- (void)viewDidLoad {
    [super viewDidLoad];

    UIButton *animation1 = [UIButton buttonWithType:UIButtonTypeCustom];
    animation1.titleLabel.font = [UIFont systemFontOfSize:15];
    [animation1 setTitle:@"縮放+旋轉" forState:UIControlStateNormal];
    [animation1 setTitleColor:[UIColor colorWithRed:0.307 green:0.397 blue:1.000 alpha:1.000] forState:UIControlStateNormal];
    [animation1 setBackgroundColor:[UIColor colorWithWhite:0.814 alpha:1.000]];
    [animation1 addTarget:self action:@selector(combinationAnimationOne) forControlEvents:UIControlEventTouchUpInside];
    
    UIButton *animation2 = [UIButton buttonWithType:UIButtonTypeCustom];
    animation2.titleLabel.font = [UIFont systemFontOfSize:15];
    [animation2 setTitle:@"軌+縮+Z旋" forState:UIControlStateNormal];
    [animation2 setTitleColor:[UIColor colorWithRed:0.307 green:0.397 blue:1.000 alpha:1.000] forState:UIControlStateNormal];
    [animation2 setBackgroundColor:[UIColor colorWithWhite:0.814 alpha:1.000]];
    [animation2 addTarget:self action:@selector(animation2Click:) forControlEvents:UIControlEventTouchUpInside];
    
    UIButton *animation3 = [UIButton buttonWithType:UIButtonTypeCustom];
    animation3.titleLabel.font = [UIFont systemFontOfSize:15];
    [animation3 setTitle:@"軌+縮+Y旋" forState:UIControlStateNormal];
    [animation3 setTitleColor:[UIColor colorWithRed:0.307 green:0.397 blue:1.000 alpha:1.000] forState:UIControlStateNormal];
    [animation3 setBackgroundColor:[UIColor colorWithWhite:0.814 alpha:1.000]];
    [animation3 addTarget:self action:@selector(animation3Click:) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:animation1];
    [self.view addSubview:animation2];
    [self.view addSubview:animation3];
    
    [animation1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.trailing.equalTo(@0);
        make.top.equalTo(@129);
        make.width.equalTo(@105);
        make.height.equalTo(@40);
    }];
    
    [animation2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.trailing.equalTo(@0);
        make.top.equalTo(animation1.mas_bottom).offset(10);
        make.width.equalTo(animation1.mas_width);
        make.height.equalTo(@40);
    }];
    
    [animation3 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.trailing.equalTo(@0);
        make.top.equalTo(animation2.mas_bottom).offset(10);
        make.width.equalTo(animation2.mas_width);
        make.height.equalTo(@40);
    }];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Private methods

- (IBAction)animation2Click:(UIButton *)sender {
    [self combinationAnimationTwoWithAxis:@"Z"];
}

- (IBAction)animation3Click:(UIButton *)sender {
    [self combinationAnimationTwoWithAxis:@"Y"];
}

#pragma mark 旋轉+縮放
- (void)combinationAnimationOne {
    
    //創建旋轉動畫
    CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    rotateAnimation.fromValue = [NSNumber numberWithFloat:0];
    rotateAnimation.toValue = [NSNumber numberWithFloat:M_PI * 8];
    rotateAnimation.duration = 1.5f;
    rotateAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    rotateAnimation.repeatCount = HUGE_VALF;
    rotateAnimation.autoreverses = YES;

    //創建縮放動畫
    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    scaleAnimation.duration = 1.5f;
    scaleAnimation.repeatCount = HUGE_VALF;
    scaleAnimation.autoreverses = YES;
    scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
    scaleAnimation.toValue = [NSNumber numberWithFloat:3.0];

    // 創建的動畫組
    CAAnimationGroup *groups = [CAAnimationGroup animation];
    groups.animations = @[rotateAnimation, scaleAnimation];
    groups.duration = 1.5f;
    groups.repeatCount = HUGE_VALF;
    groups.autoreverses = YES;
    
    [self.animationView.layer addAnimation:groups forKey:@"CombinationAnimation"];
}

#pragma mark 移動+旋轉+縮放
- (void)combinationAnimationTwoWithAxis:(NSString *)axis {
    
    //創建移動軌跡
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:self.animationView.layer.position];
    [path addLineToPoint:CGPointMake(SCREEN_WIDTH - self.animationView.width / 2.0, SCREEN_HEIGHT / 2.0)];
    [path addLineToPoint:CGPointMake(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT - self.animationView.width / 2.0)];
    [path addLineToPoint:CGPointMake(self.animationView.width / 2.0, SCREEN_HEIGHT / 2.0)];
    [path addLineToPoint:CGPointMake(SCREEN_WIDTH / 2.0, 64 + self.animationView.width / 2.0)];
    [path closePath];
    
    //創建關鍵幀動畫
    CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    pathAnimation.path = path.CGPath;           //將路徑給予動畫
    pathAnimation.duration = 8.0;               //持續時間
    pathAnimation.repeatCount = HUGE_VALF;      // 重復次數
    
    //創建縮放動畫
    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    scaleAnimation.duration = 1.5f;
    scaleAnimation.repeatCount = HUGE_VALF;
    scaleAnimation.autoreverses = YES;
    scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
    scaleAnimation.toValue = [NSNumber numberWithFloat:3.0];

    //創建旋轉動畫
    CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:[axis isEqualToString:@"Z"] ? @"transform.rotation" :  @"transform.rotation.y"];
    rotateAnimation.fromValue = [NSNumber numberWithFloat:0];
    rotateAnimation.toValue = [NSNumber numberWithFloat:12];
    rotateAnimation.duration = 0.5f;
    rotateAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    rotateAnimation.repeatCount = 4;
    rotateAnimation.autoreverses = YES;

    // 創建的動畫組
    CAAnimationGroup *groups = [CAAnimationGroup animation];
    groups.animations = @[pathAnimation, rotateAnimation, scaleAnimation];
    groups.duration = 8.0;
    groups.repeatCount = HUGE_VALF;
    groups.autoreverses = YES;
    
    [self.animationView.layer addAnimation:groups forKey:@"CombinationAnimation"];
}

#pragma mark - WBBaseAnimationDelegate methods

- (void)starAnimation {
    [self combinationAnimationTwoWithAxis:@"Z"];
}

- (void)removeAnimation {
    [self.animationView.layer removeAllAnimations];
}

@end

 

 

組合動畫中,我們會有這樣的思考,在創建 縮放動畫 或者 旋轉動畫的時候,已經設置了 動畫的持續時間 duration , 那麼在創建動畫組的時候,也設置了同樣的屬性,那麼這樣有什麼不同呢? 還是依據時間最長的來呢?

其實我們可以這樣想,比如設置了 旋轉動畫 的時間為 0.5f , 即是單位時間內執行一次動畫,所需0.5f ,repeatCount 執行4次 ,那麼動畫組設置 8.0f, 那麼意思就是,旋轉的動畫會執行 2.0f ,所以像圖中, 矩形在運動到最左邊的邊緣時,就不在旋轉了,只執行運動和縮放的動畫了,即動畫之間,還是可以分開管理的,可以設定在某一個時刻停止或繼續執行某個動畫 ,時間可以控制的,並不沖突。

 

 

 

 

 

\

 

 

 

彈簧動畫

創建WBSpringAnimationVC ,繼承於WBBaseAnimationVC , .m 如下

 

 

 

#pragma mark - Private methods

- (void)setupUI {

    self.animationView.hidden = YES;
    self.starAnimationButton.hidden = YES;
    self.removeAnimationButton.hidden = YES;
    
    self.basketballImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Basketball"]];
    [self.view addSubview:self.basketballImageView];
    [self.basketballImageView  mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(self.view.mas_centerX);
        make.centerY.equalTo(self.view.mas_centerY);
        make.width.height.equalTo(@50);
    }];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    UITouch *touch=touches.anyObject;
    
    CGPoint location= [touch locationInView:self.view];
    
    /**
     *  彈性動畫
     *  Duration    動畫持續時間
     *  delay       動畫延遲執行時間
     *  Damping     彈性阻尼,范圍0.0~1.0 ,值越小,彈簧振幅越大
     *  Velocity    彈性復位的速度
     *  options     動畫類型
     *
     - returns:
     */
    [UIView animateWithDuration:5.0 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveLinear animations:^{
        
        self.basketballImageView.center = location;
    } completion:^(BOOL finished) {
        
    }];
}

 

 

 

\

 

 

 

轉場動畫

 

創建WBTransitionsAnimationVC ,繼承於WBBaseAnimationVC , .m 如下

 

 

 

#import "WBTransitionsAnimationVC.h"
#import "WBTransitionsCell.h"

@interface WBTransitionsAnimationVC () 

@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) NSArray *> *titles;
@property (nonatomic, strong) NSArray *imagesNamed;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UILabel *pageLabel;

@property (nonatomic, assign) NSInteger currentIndex;           //當前第幾張圖片
@property (nonatomic, copy) NSString *currentAnimationType;     //當前動畫類型

@end

@implementation WBTransitionsAnimationVC

- (void)viewDidLoad {
    [super viewDidLoad];

    [self setupUI];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

#pragma mark - Private methods

- (void)setupUI {
    
    self.animationView.hidden = YES;
    self.starAnimationButton.hidden = YES;
    self.removeAnimationButton.hidden = YES;
    
    self.titles = @[
                    @{@"fade" : @"淡出效果"} ,
                    @{@"movein" : @"新視圖移動到舊視圖上"} ,
                    @{@"push" : @"新視圖推出舊視圖"} ,
                    @{@"reveal" : @"移開舊視圖顯示新視圖"} ,
                    @{@"cube" : @"立方體翻轉效果"} ,
                    @{@"oglFlip" : @"翻轉效果"} ,
                    @{@"suckEffect" : @"收縮效果"} ,
                    @{@"rippleEffect" : @"水滴波紋效果"} ,
                    @{@"pageCurl" : @"向上翻頁效果"} ,
                    @{@"pageUnCurl" : @"向下翻頁效果"} ,
                    @{@"cameralIrisHollowOpen" : @"攝像頭打開效果"} ,
                    @{@"cameraIrisHollowClose" : @"攝像頭關閉效果"}
                    ];
  
    self.imagesNamed = @[
                         @"picture1" ,
                         @"picture2" ,
                         @"picture3" ,
                         @"picture4" ,
                         @"picture5" ,
                         @"picture6" ,
                         @"picture7" ,
                         @"picture8" 
                         ];
    
    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    [layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.view.width, self.view.height) collectionViewLayout:layout];
    [_collectionView registerClass:[WBTransitionsCell class] forCellWithReuseIdentifier:[WBTransitionsCell reuseIdentifier]];
    _collectionView.backgroundColor = [UIColor clearColor];
    _collectionView.alwaysBounceVertical = NO;
    _collectionView.showsHorizontalScrollIndicator = NO;
    _collectionView.delegate = self;
    _collectionView.dataSource = self;
    [self.view addSubview:self.collectionView];
    
    self.imageView = [[UIImageView alloc] init];
    _imageView.contentMode = UIViewContentModeScaleAspectFit;
    [self.view addSubview:self.imageView];
    
    self.pageLabel = [[UILabel alloc] init];
    self.pageLabel.textColor = [UIColor redColor];
    self.pageLabel.textAlignment = NSTextAlignmentCenter;
    self.pageLabel.font = [UIFont systemFontOfSize:17];
    [self.view addSubview:self.pageLabel];

    [self.view setNeedsLayout];
    [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(@70);
        make.leading.trailing.equalTo(@0);
        make.height.equalTo(@50);
    }];

    [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.collectionView.mas_bottom).offset(40);
        make.leading.equalTo(@30);
        make.trailing.equalTo(@(-30));
        make.bottom.equalTo(@(-40));
    }];
    
    [self.pageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.imageView.mas_bottom);
        make.bottom.equalTo(@0);
        make.centerX.equalTo(self.view.mas_centerX);
        make.width.equalTo(@200);
    }];
    [self.view layoutIfNeeded];
    
    UISwipeGestureRecognizer *leftSwipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(leftSwipe:)];
    leftSwipeGesture.direction = UISwipeGestureRecognizerDirectionLeft;
    [self.view addGestureRecognizer:leftSwipeGesture];
    
    UISwipeGestureRecognizer *rightSwipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(rightSwipe:)];
    rightSwipeGesture.direction = UISwipeGestureRecognizerDirectionRight;
    [self.view addGestureRecognizer:rightSwipeGesture];
    
    [self setupDefaultValue];
}

#pragma mark - Private methods

- (void)setupDefaultValue {
    
    //默認圖
    self.currentIndex = 0;
    self.imageView.image = [self fetchCurrentImageWithIndex:self.currentIndex];
    [self updatePageWithIndex:self.currentIndex];
    //默認動畫類型
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    [self updateAnimationTypeWithIndexPath:indexPath];
}

// 獲取image
- (UIImage *)fetchCurrentImageWithIndex:(NSInteger)index {
    return [UIImage imageNamed:self.imagesNamed[index]];
}

// 更新動畫類型 及 UI
- (void)updateAnimationTypeWithIndexPath:(NSIndexPath *)indexPath {

    self.currentAnimationType = self.titles[indexPath.row].allKeys.firstObject;
    WBTransitionsCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:[WBTransitionsCell reuseIdentifier] forIndexPath:indexPath];
    cell.selected = YES;
}

- (void)leftSwipe:(UISwipeGestureRecognizer *)gesture{
    [self transitionAnimationDirection:YES];
}

- (void)rightSwipe:(UISwipeGestureRecognizer *)gesture{
    [self transitionAnimationDirection:NO];
}

// 執行動畫
- (void)transitionAnimationDirection:(BOOL)isNext {
    
    CATransition *transition = [[CATransition alloc] init];
    //設置動畫類型
    transition.type = self.currentAnimationType;
    //設置動畫時常
    transition.duration = 1.0f;
    //設置方向
    if (isNext) {
        transition.subtype = kCATransitionFromRight;
        self.currentIndex += 1;
    } else {
        transition.subtype = kCATransitionFromLeft;
        self.currentIndex -= 1;
    }
    
    if (self.currentIndex == -1) {
        self.currentIndex = self.imagesNamed.count - 1;
    } else if (self.currentIndex == self.imagesNamed.count) {
        self.currentIndex = 0;
    }
    [self updatePageWithIndex:self.currentIndex];
    self.imageView.image = [self fetchCurrentImageWithIndex:self.currentIndex];
    [self.imageView.layer addAnimation:transition forKey:@"transitionAnimation"];
}

// 更新 Page
- (void)updatePageWithIndex:(NSInteger)index {
    self.pageLabel.text = [NSString stringWithFormat:@"%ld / %ld", index + 1, self.imagesNamed.count];
}

#pragma mark - UICollectionViewDataSource methods

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return self.titles.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    WBTransitionsCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[WBTransitionsCell reuseIdentifier] forIndexPath:indexPath];
    [cell setupWithTitle:self.titles[indexPath.row].allValues.firstObject];
    return cell;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    CGFloat minWidth = getTextWidth([UIFont systemFontOfSize:15], self.titles[indexPath.row].allValues.firstObject, 50).width;
    return CGSizeMake(minWidth + 20, collectionView.height);
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    
    return UIEdgeInsetsMake(0, 0, 0, 0);
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{
    
    return CGSizeMake(0, 0);
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return 10;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    
    [self updateAnimationTypeWithIndexPath:indexPath];
}

- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
    
    WBTransitionsCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[WBTransitionsCell reuseIdentifier] forIndexPath:indexPath];
    cell.selected = NO;
}

@end

 

轉場動畫中, 上面的選項 可以選擇需要的轉場動畫類型。
 

 

 

\

 

 

 

添加購物車動畫

 

將動畫封裝在 WBBaseAnimations中. .h 接口如下

 

 

#import 

@interface WBBaseAnimations : NSObject

+ (instancetype)sharedInstance;

/**
 *  加入購物車 動畫
 *
 *  @param view        需要動畫的視圖
 *  @param starRect    動畫的起始位置 Rect (相對於window的位置)
 *  @param finishPoint 動畫的終點 Point
 *  @param completed   動畫完成回調
 */
- (void)starAnimationWithView:(UIView *)view
                     starRect:(CGRect)starRect
                  finishPoint:(CGPoint)finishPoint
               completedBlock:(void (^)(BOOL finish))completed;

/**
 *  搖一搖動畫
 *
 *  @param view      需要動畫的視圖
 *  @param completed 動畫完成回調
 */
- (void)shakeAnimationWithView:(UIView *)view
                completedBlock:(void (^)(BOOL finish))completed;

@end

 

 

在WBShoppingCartVC 中使用購物車動畫, .m 如下

 

 

 

#import "WBShoppingCartVC.h"
#import "WBShoppingCartCell.h"
#import "WBBaseAnimations.h"

@interface WBShoppingCartVC ()

@property (strong, nonatomic) IBOutlet UITableView *tableView;

@end

@implementation WBShoppingCartVC

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Private methods

- (void)addCartAnimationWithView:(UIView *)view {

    UIWindow *window = [[UIApplication sharedApplication].delegate window];
    CGRect goodsImageRect = [view convertRect:view.bounds toView:window];
    //動畫期間禁止交互,可以一次只執行一次動畫.
//    window.userInteractionEnabled = NO;
    
    WBBaseAnimations *animation = [WBBaseAnimations sharedInstance];
    [animation starAnimationWithView:view starRect:goodsImageRect finishPoint:CGPointMake(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT - 49) completedBlock:^(BOOL finish) {
        if (finish) {
            UIView *tabbarView = self.tabBarController.tabBar.subviews[2];
            [animation shakeAnimationWithView:tabbarView completedBlock:^(BOOL finish) {
                if (finish) {
//                    window.userInteractionEnabled = YES;
                }
            }];
        }
    }];
}

#pragma mark - UITableViewDelegate methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 10;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    WBShoppingCartCell *cell = [tableView dequeueReusableCellWithIdentifier:@"shoppingCartCell" forIndexPath:indexPath];
    [cell setAddCartGoodsImageViewBlock:^(UIImageView *imageView) {
        [self addCartAnimationWithView:imageView];
    }];
    
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}


@end

 

\

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved