UIView动画

UIView动画也称为隐式动画,动画过程即frame等属性发生改变的过程,主要包括首尾式动画(UIViewAnimation)、block动画(UIViewAnimationWithBlocks)、帧动画(UIViewKeyframeAnimations)

一、首尾式动画(UIViewAnimation)

通常情况,如果只是修改控件的属性,使用首尾式动画还是比较方便的,但是如果需要在动画完成后做后续处理,就不是那么方便了,这时可以使用block动画进行操作。

// 开始动画,animationID是给该动画一标识相当于起了一个名字,context是传递给 启动/停止选择器 的信息
+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context; 

// 启动动画
+ (void)commitAnimations; 

//设置动画代理,默认为nil
+ (void)setAnimationDelegate:(nullable id)delegate;   

//设置动画将要开始时的选择器方法。推荐方法: -animationWillStart:(NSString *)animationID context:(void *)context
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;   
 
// 设置动画已经结束时的选择器方法。推荐方法: -animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;                  

// 设置动画持续时间,默认为0.2秒
+ (void)setAnimationDuration:(NSTimeInterval)duration; 

// 设置延迟几秒开始动画,默认为0
+ (void)setAnimationDelay:(NSTimeInterval)delay;                    

// 设置动画开始的时间。默认是现在,即立即执行。
+ (void)setAnimationStartDate:(NSDate *)startDate;                  

// 设置动画运动曲线,控制动画速度,是枚举类型UIViewAnimationCurve,默认是UIViewAnimationCurveEaseInOut
/**
typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
    UIViewAnimationCurveEaseInOut,     // 慢进慢出,中间速度快
    UIViewAnimationCurveEaseIn,        // 开始慢,由慢而快
    UIViewAnimationCurveEaseOut,       // 结束时慢,由快而慢
    UIViewAnimationCurveLinear,        // 线性匀速
};
*/
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;              

// 设置动画重复次数,默认为零
+ (void)setAnimationRepeatCount:(float)repeatCount;                 

// 是否使用自动返回到原始状态的动画,当repeat count 不为零时才有作用,默认为NO
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;    

// 设置如果开始一个动画正在播放的时候,另外一个动画开始了,是否在上一个动画现在的状态(还未完成状态)开始下一个动画,
// 这样会是一个动画“堆积”的过程,默认是只当上一个动画结束动画状态后再开始新的动画,默认为NO
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;  

// 设置View的转场动画方向,枚举类型UIViewAnimationTransition
/**
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
    UIViewAnimationTransitionNone,  // 无转场动画
    UIViewAnimationTransitionFlipFromLeft,  // 从左翻转
    UIViewAnimationTransitionFlipFromRight,  // 从右翻转
    UIViewAnimationTransitionCurlUp,  //  从下向上
    UIViewAnimationTransitionCurlDown,  //  从上向下
};
*/
// cache :是否使用试图缓存
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;  

//  是否允许动画,默认是yes
+ (void)setAnimationsEnabled:(BOOL)enabled; 

//  代码块内执行无动画变换,他与-setAnimationEnabled:的区别在于前者使整个首尾之间均无动画,后者可以针对个别变换使之无动画。
+ (void)performWithoutAnimation:(void (NS_NOESCAPE ^)(void))actionsWithoutAnimation NS_AVAILABLE_IOS(7_0);

// 9.0后新添加方法,获取父类持续时间。
+ (NSTimeInterval)inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
                        

e.g:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    squareView = [[UIView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)];
    squareView.backgroundColor = [UIColor redColor];
    [self.view addSubview:squareView];
    UIButton * topButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 600, 100, 50)];
    [topButton addTarget:self action:@selector(topButtonAction:) forControlEvents:(UIControlEventTouchUpInside)];
    topButton.backgroundColor = [UIColor redColor];
    [topButton setTitle:@"首尾式动画" forState:(UIControlStateNormal)];
    [self.view addSubview:topButton];
}
- (void)topButtonAction:(UIButton *)sender
{
    [UIView beginAnimations:@"oneAnimation" context:@"I am Pass Context"];
    [UIView setAnimationDuration:3.0f];
//    [UIView setAnimationsEnabled:NO];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationWillStartSelector:@selector(animationWillStart: context:)];
    [UIView setAnimationDelay:1.0f];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [UIView setAnimationRepeatCount:2];
    [UIView setAnimationRepeatAutoreverses:YES];
//    [UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:squareView cache:NO];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop: finished: context:)];
    squareView.alpha = 0.5;
    squareView.backgroundColor = [UIColor blueColor];
    CGAffineTransform transform_0 = CGAffineTransformMakeTranslation(200, 0);
    CGAffineTransform transform_1 = CGAffineTransformMakeRotation(M_PI);
    CGAffineTransform transform_all = CGAffineTransformConcat(transform_1, transform_0);
    squareView.transform = transform_all;
    [UIView commitAnimations];
}
-(void)animationWillStart:(NSString *)animationID context:(void *)context
{
    NSLog(@"animationID = %@, context = %@", animationID, context);
}
-(void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
    NSLog(@"animationID = %@, finished = %@, context = %@", animationID, finished, context);
}
UIView动画_第1张图片
运行,点击按钮后控制台打印结果,因为重复次数为2,故开始/结束代理方法均走了两次
UIView动画_第2张图片
普通view动画效果图示例

在这里特别注意的是:当设置了-setAnimationsEnabled:为NO时,动画将消失,同时代理方法将只会运行已经停止的方法(-(void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context),而无法检测将要开始的方法(-(void)animationWillStart:(NSString *)animationID context:(void *)context)

二、block动画(UIViewAnimationWithBlocks)

在View动画中最常用的还是block动画,相对于首尾式动画来说可以简单的操作动画完成后的事物。

// 参数:duration-持续时间、delay-延迟时间、options-动画类型,其中options为枚举类型UIViewAnimationOptions:
/**
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
//常规动画属性设置(可以同时选择多个进行)
    UIViewAnimationOptionLayoutSubviews            = 1 <<  0, // 动画过程中保证子视图跟随一起运动
    UIViewAnimationOptionAllowUserInteraction      = 1 <<  1, // 动画过程中允许用户交互
    UIViewAnimationOptionBeginFromCurrentState     = 1 <<  2, //视图从当前状态开始                    
    UIViewAnimationOptionRepeat                    = 1 <<  3, // 重复动画
    UIViewAnimationOptionAutoreverse               = 1 <<  4, // 动画运行到结束点后仍然以动画方式回到初始点
    UIViewAnimationOptionOverrideInheritedDuration = 1 <<  5, // 忽略嵌套的持续时间
    UIViewAnimationOptionOverrideInheritedCurve    = 1 <<  6, // 忽略嵌套的曲线设置
    UIViewAnimationOptionAllowAnimatedContent      = 1 <<  7, // 动画过程中重绘视图 (仅限转场动画)
    UIViewAnimationOptionShowHideTransitionViews   = 1 <<  8, // 视图切换时直接隐藏旧视图、显示新视图,而不是将旧视图从父视图移除(仅限转场动画)
    UIViewAnimationOptionOverrideInheritedOptions  = 1 <<  9, // 不继承任何父动画设置动画、类型类型等
    
// 动画曲线速度控制-与首尾式曲线设置一样(只可从其中选择一个)
    UIViewAnimationOptionCurveEaseInOut            = 0 << 16, // default
    UIViewAnimationOptionCurveEaseIn               = 1 << 16,
    UIViewAnimationOptionCurveEaseOut              = 2 << 16,
    UIViewAnimationOptionCurveLinear               = 3 << 16,
    
// 转场动画设置(仅适用于转场动画设置,可以从中选择一个进行设置)
    UIViewAnimationOptionTransitionNone            = 0 << 20, // default,无转场动画
    UIViewAnimationOptionTransitionFlipFromLeft    = 1 << 20, // 从左向右翻转
    UIViewAnimationOptionTransitionFlipFromRight   = 2 << 20, // 从右向左翻转
    UIViewAnimationOptionTransitionCurlUp          = 3 << 20, // 从下向上翻页(不是翻转!!!)
    UIViewAnimationOptionTransitionCurlDown        = 4 << 20,// 从上向下翻页
    UIViewAnimationOptionTransitionCrossDissolve   = 5 << 20, // 溶解显示新视图
    UIViewAnimationOptionTransitionFlipFromTop     = 6 << 20,// 从上向下翻转
    UIViewAnimationOptionTransitionFlipFromBottom  = 7 << 20,// 从下向上翻转
} NS_ENUM_AVAILABLE_IOS(4_0);
*/
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
// 与上面一个方法相比将延迟时间设为了0,动画效果固定为UIViewAnimationOptionLayoutSubviews | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionTransitionNone
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0
//  将完成后的block给去掉了
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL
#pragma   ---------以上是普通动画方法------------

//相对于普通方法多了一个阻尼(dampingRatio),范围是(0-1),同时多了一个初始弹簧速度(一般是0);
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
#pragma   ---------------以上是弹簧动画方法-----------------

// 普通转场动画,针对某一个指定的视图
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

// 该方法是将toView添加到fromView的父视图中的动画效果。结束后fromView会从它的父视图上被移除
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview
#pragma   -----------------以上是转场动画方法-------------------

// 在一个或者一组视图上执行系统规定的动画,在这里的系统规定是指开始时间、延时时间、持续时间等属性会与系统默认的相同,执行效果就是模糊化消失。当动画结束后这一组视图会在其父视图中被移除!
+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray<__kindof UIView *> *)views options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))parallelAnimations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

e.g:

@interface ViewAnimationViewController ()
{
    UIView * squareView;
    UIView * transformView;
}
@end

@implementation ViewAnimationViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    squareView = [[UIView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)];
    squareView.backgroundColor = [UIColor redColor];
    [self.view addSubview:squareView];
    
    transformView = [[UIView alloc] initWithFrame:CGRectMake(200, 200, 100, 100)];
    transformView.backgroundColor = [UIColor orangeColor];
    
    NSArray * titleArray = @[@"普通block动画", @"弹簧block动画", @"转场block动画", @"系统block动画"];
    for (int i = 0; i < titleArray.count; i++) {
        UIButton * topButton = [[UIButton alloc] initWithFrame:CGRectMake(12+(i*90), 500, 80, 30)];
        [topButton addTarget:self action:@selector(topButtonAction:) forControlEvents:(UIControlEventTouchUpInside)];
        topButton.tag = 10000 + i;
        topButton.titleLabel.font = [UIFont systemFontOfSize:12];
        topButton.backgroundColor = [UIColor redColor];
        [topButton setTitle:titleArray[i] forState:(UIControlStateNormal)];
        [self.view addSubview:topButton];
    }
}

- (void)topButtonAction:(UIButton *)sender
{
    if (sender.tag == 10000) {
        [UIView animateWithDuration:2.0 delay:0 options:UIViewAnimationOptionLayoutSubviews | UIViewAnimationOptionAutoreverse |UIViewAnimationCurveEaseIn | UIViewAnimationOptionTransitionNone animations:^{
            squareView.backgroundColor = [UIColor blueColor];
            CGAffineTransform transform_0 = CGAffineTransformMakeTranslation(150, 0);
            CGAffineTransform transform_1 = CGAffineTransformMakeRotation(M_PI);
            CGAffineTransform transform_all = CGAffineTransformConcat(transform_1, transform_0);
            squareView.transform = transform_all;
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:2.0 animations:^{
                squareView.frame = CGRectMake(100, 400, 100, 100);
            }];
        }];
    }
    if (sender.tag == 10001) {
        [UIView animateWithDuration:2.0 delay:0.0 usingSpringWithDamping:0.5 initialSpringVelocity:10 options:0 animations:^{
            squareView.frame = CGRectMake(100, 200, 100, 100);
        } completion:^(BOOL finished) {
        }];
    }
    if (sender.tag == 10002) {
        [UIView transitionFromView:squareView toView:transformView duration:2.0 options:UIViewAnimationOptionTransitionCrossDissolve completion:^(BOOL finished) {
            [UIView transitionWithView:transformView duration:2.0 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
                transformView.backgroundColor = [UIColor purpleColor];
            } completion:^(BOOL finished) {
            }];
        }];
    }
    if (sender.tag == 10003) {
        [UIView performSystemAnimation:UISystemAnimationDelete onViews:@[transformView] options:UIViewAnimationOptionTransitionCurlDown  animations:^{
            transformView.transform = CGAffineTransformMakeTranslation(-150, 0);
        } completion:^(BOOL finished) {
            
            NSLog(@"%@", NSStringFromClass([transformView.superview class]));
            NSLog(@"%@", [transformView.superview class]);
        }];
    }
}
UIView动画_第3张图片
block动画效果图示例

三、帧动画(UIViewKeyframeAnimations)

运用场景:帧动画常用于同一个视图的分段动画,和用于不同视图的组合动画。

// 除了参数options外其他与普通block动画大抵相同,其中options是枚举类型UIViewKeyframeAnimationOptions
/*
typedef NS_OPTIONS(NSUInteger, UIViewKeyframeAnimationOptions) {
    UIViewKeyframeAnimationOptionLayoutSubviews            = UIViewAnimationOptionLayoutSubviews,
    UIViewKeyframeAnimationOptionAllowUserInteraction      = UIViewAnimationOptionAllowUserInteraction, 
    UIViewKeyframeAnimationOptionBeginFromCurrentState     = UIViewAnimationOptionBeginFromCurrentState, 
    UIViewKeyframeAnimationOptionRepeat                    = UIViewAnimationOptionRepeat, 
    UIViewKeyframeAnimationOptionAutoreverse               = UIViewAnimationOptionAutoreverse, 
    UIViewKeyframeAnimationOptionOverrideInheritedDuration = UIViewAnimationOptionOverrideInheritedDuration, 
    UIViewKeyframeAnimationOptionOverrideInheritedOptions  = UIViewAnimationOptionOverrideInheritedOptions, 
    
#pragma -----------以上与UIViewAnimationOptions中的一部分对应,在此不多赘述。
    UIViewKeyframeAnimationOptionCalculationModeLinear     = 0 << 10, // default,线性的计算模式,按顺序连续变换。
    UIViewKeyframeAnimationOptionCalculationModeDiscrete   = 1 << 10, // 离散的计算模式,分散的点式变换。
    UIViewKeyframeAnimationOptionCalculationModePaced      = 2 << 10,// 均匀执行计算模式,不管你添加帧动画时如何设置的起始时间和持续时间,都会在持续的总时间内均匀执行动画。
    UIViewKeyframeAnimationOptionCalculationModeCubic      = 3 << 10, // 这个从效果上看好像和线性的差不多~
    UIViewKeyframeAnimationOptionCalculationModeCubicPaced = 4 << 10 // 这个就是上面两个的组合体~~
} NS_ENUM_AVAILABLE_IOS(7_0);
*/
// 创建关键帧域的帧动画
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
// 添加关键帧动画 ,起始时间和持续时间值均在0.0和1.0之间,是指以关键帧域所设置的持续时间为对比的相对时间。e.g:frameStartTime若为0,则从第零秒开始,若为0.2,则从总持续时间的五分之一处开始。同理frameDuration若为0.2 则该帧动画持续时间占总持续时间的五分之一。
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations NS_AVAILABLE_IOS(7_0); 
UIView动画_第4张图片
**盗用网上的一张图,虽然没看懂~~**

e.g:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    squareView = [[UIView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)];
    squareView.backgroundColor = [UIColor redColor];
    [self.view addSubview:squareView];
    
    UIButton * topButton = [[UIButton alloc] initWithFrame:CGRectMake(200, 500, 80, 30)];
    [topButton addTarget:self action:@selector(topButtonAction:) forControlEvents:(UIControlEventTouchUpInside)];
    topButton.titleLabel.font = [UIFont systemFontOfSize:12];
    topButton.backgroundColor = [UIColor redColor];
    [topButton setTitle:@"view帧动画" forState:(UIControlStateNormal)];
    [self.view addSubview:topButton];
}

- (void)topButtonAction:(UIButton *)sender
{
    [UIView animateKeyframesWithDuration:10.0 delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
        [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.25 animations:^{
            squareView.backgroundColor = [UIColor yellowColor];
            squareView.transform = CGAffineTransformMakeScale(2.0, 2.0);
        }];
        [UIView addKeyframeWithRelativeStartTime:0.25 relativeDuration:0.25 animations:^{
            squareView.backgroundColor = [UIColor blueColor];
            squareView.transform = CGAffineTransformMakeTranslation(100, 0);
        }];
        [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.25 animations:^{
            squareView.backgroundColor = [UIColor purpleColor];
            squareView.transform = CGAffineTransformMakeRotation(M_PI);
        }];
        [UIView addKeyframeWithRelativeStartTime:0.75 relativeDuration:0.25 animations:^{
            squareView.backgroundColor = [UIColor cyanColor];
            squareView.transform = CGAffineTransformMakeScale(0.5, 0.5);
        }];
    } completion:^(BOOL finished) {
    }];
}
UIView动画_第5张图片
帧动画效果展示

四、补充:UIImageView的序列帧动画

 UIImageView有一组属性方法可以播放一组图片,类似于GIF播放效果。---其实可以完全被GIF取代~~

@property (nullable, nonatomic, copy) NSArray *animationImages; 
@property (nullable, nonatomic, copy) NSArray *highlightedAnimationImages NS_AVAILABLE_IOS(3_0); 
 //一个周期持续时间. 默认是图片数量*1/30秒,即每秒播放30张图片(30fps)
@property (nonatomic) NSTimeInterval animationDuration;        
@property (nonatomic) NSInteger      animationRepeatCount; // 默认为0,无限循环    
- (void)startAnimating;// 开始动画
- (void)stopAnimating;// 结束动画
- (BOOL)isAnimating; // 判断是否处于动画状态。

在此就不举例了~

你可能感兴趣的:(UIView动画)