iOS动画(2):UIView动画

UIView动画在平常的使用场景中比较普遍,UIView的属性改变时使用UIView动画过渡会比较自然,用起来也比较简单。

UIViewAnimationUIViewAnimationWithBlocksUIViewKeyframeAnimations三种实现方式。

1、UIViewAnimation

下面是UIViewAnimation的基本调用方法(方法已做备注):

@interface UIView(UIViewAnimation)

//开始动画。传递的context值会传递给代理的start/did stop方法中。
+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context; 

//和beginAnimations方法成对出现。代表动画开始和执行,动画内容放在两个个方法中间。
+ (void)commitAnimations;          

// 设置动画代理,当动画开始或者结束时会发消息给代理对象。默认是nil。
+ (void)setAnimationDelegate:(nullable id)delegate;        

//动画即将开始时,执行selector,并且把beginAnimations:context:中传入的参数传进selector              
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;              

 //动画即将结束时,执行selector,并且把beginAnimations:context:中传入的参数传进selector     
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;               

//动画的持续时间,以秒为单位。默认是0.2.
+ (void)setAnimationDuration:(NSTimeInterval)duration;              

//动画延迟。默认是0。
+ (void)setAnimationDelay:(NSTimeInterval)delay;                  

//默认是now. 
+ (void)setAnimationStartDate:(NSDate *)startDate;                

//动画的节奏控制。默认是UIViewAnimationCurveEaseInOut。
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;             

//动画重复次数。默认是0.
+ (void)setAnimationRepeatCount:(float)repeatCount;       

//动画是否逆向运行。如果是YES的话,动画会按照原来的运动轨迹逆向返回。默认是NO。
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;   

//动画是否从当前状态开始。默认是NO。如果为YES,那么动画在运行过程中当前视图的位置将会作为新的动画的开始状态。如果设置为NO,新动画将使用视图最後状态的位置作为开始状态。
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;  

//设置view的过渡效果, transition是设定过渡类型, cache为YES时代表使用视图缓存。
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;  

//是否激活动画。如果是YES,就激活动画,当动画参数没有被激活那么动画属性的改变将被忽略。默认是YES。
+ (void)setAnimationsEnabled:(BOOL)enabled;                        

#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) BOOL areAnimationsEnabled;
#else
+ (BOOL)areAnimationsEnabled;
#endif
+ (void)performWithoutAnimation:(void (NS_NOESCAPE ^)(void))actionsWithoutAnimation NS_AVAILABLE_IOS(7_0);

#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) NSTimeInterval inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#else
+ (NSTimeInterval)inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#endif

@end

UIViewAnimation使用示例:

    UIImage * image = [UIImage imageNamed:@"icon1"];
    
    [imageView setImage:image];
    
    //动画开始前视图状态
    imageView.frame = CGRectMake(ScreenWidth/2-image.size.width/2, (ScreenHeight-image.size.height)/2,image.size.width,image.size.height);
    
    [UIView beginAnimations:nil context:nil];
    
    [UIView setAnimationDuration:1.0f];
    
    image = [UIImage imageNamed:@"icon2"];
    
    [imageView setImage:image];
    
    //视图最终状态
    imageView.frame = CGRectMake(ScreenWidth/2-25, ScreenHeight-50, 50, 50);
    
    [UIView commitAnimations];

2、UIViewAnimationWithBlocks

UIViewAnimationWithBlocks的方法函数如下:

@interface UIView(UIViewAnimationWithBlocks)

/**
block动画,可以设置动画时长、动画延迟、动画选项、动画结束状态、动画完成后最终状态,
可根据自己实际需要选择下面3种实现方式
**/
+ (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);

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL

//视图过渡动画
+ (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);

//视图间过渡动画
+ (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

//弹簧动画
+ (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);

//删除视图动画
+ (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);

@end

主要分为简单的block动画、视图过渡动画、视图间过渡动画、弹簧动画和删除动画。

注:弹簧动画参数dampingRatio、velocity分别是阻尼大小、形变速度。
dampingRatio:实际指弹簧动画的摩擦力大小。值的范围是0.0~1.0。当阻尼大小越小代表阻力越小,反之则阻力越大,阻力越小弹簧动画的幅度就越大,越大弹簧幅度就越小,与现实中弹簧拉伸的道理是一样的。
velocity:指弹簧的变化的速度。速度越大,变化越快。

下面看下不同动画的代码示例:

(1)简单的block动画
-(void)AnimationWithSimpleBlocks{
    
    UIImage * image = [UIImage imageNamed:@"heart"];
    
    [imageView setImage:image];
    
    imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2, 150+(ScreenHeight-150-image.size.height)/2,image.size.width,image.size.height);
    
    [UIView animateWithDuration:1.0f delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        //动画终点
        imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2, 150+(ScreenHeight-150-image.size.height)/2, image.size.width+20, image.size.height+20);
        
    } completion:^(BOOL finished) {
        
        //view最终状态(UIView会从动画结束状态转换到此处设定的状态,在转换过程中没有动画效果)
        imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2,  150+(ScreenHeight-150-image.size.height)/2,image.size.width,image.size.height);
        
    }];

}

(2)视图过渡动画示例:
-(void)AnimationWithTransitionBlocks{
    
    UIImage * image = [UIImage imageNamed:@"heart"];
    
    [imageView setImage:image];
    
    imageView.frame = CGRectMake(0, (ScreenHeight-image.size.height)/2,image.size.width,image.size.height);
    
    //带有过渡效果
    [UIView transitionWithView:imageView duration:1.5f options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
        
        //动画终点
        imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2, 150+(ScreenHeight-150-image.size.height)/2, image.size.width+20, image.size.height+20);

    } completion:^(BOOL finished) {
        
    }];
    
}


(3)视图之间过渡动画代码示例:
-(void)AnimationBetweenViews{
    UIView *view1 = [[UIView alloc]initWithFrame:self.view.frame];
    
    view1.backgroundColor = [UIColor yellowColor];
    
    UIView *view2 = [[UIView alloc]initWithFrame:self.view.frame];
    
    view2.backgroundColor = [UIColor orangeColor];
    
    [self.view addSubview:view1];
    
    [self.view addSubview:view2];
    
    [UIView transitionFromView:view1  toView:view2 duration:1.5f options:UIViewAnimationOptionTransitionFlipFromLeft completion:^(BOOL finished) {
        
        [view1 removeFromSuperview];
        
        [view2 removeFromSuperview];
        
    }];
}
(4)弹簧动画示例
-(void)SpringAnimation{
    
    UIImage * image = [UIImage imageNamed:@"heart"];
    
    [imageView setImage:image];
    
    imageView.frame = CGRectMake(0, 150+(ScreenHeight-150-image.size.height)/2,image.size.width,image.size.height);
    
    [UIView animateWithDuration:1.0f delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:0.5 options:0 animations:^{
        
        //动画终点
        imageView.frame = CGRectMake((ScreenWidth-image.size.width)/2, 150+(ScreenHeight-150-image.size.height)/2, image.size.width+20, image.size.height+20);
        
    } completion:^(BOOL finished) {
        
        
    }];

}

运行结果如下:

UIView Block动画.gif

注:UIView的简单动画可以通过这两种方式来实现,如果是比较复杂的动画的话使用CAKeyframeAnimations实现会更方便。

3、CAKeyframeAnimations

CAKeyframeAnimations函数如下:

@interface UIView (UIViewKeyframeAnimations)

//设定动画时长、动画延迟、关键帧选项、关键帧
+ (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);

//添加关键帧动画的开始时间、帧动画在整个动画的比例
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations NS_AVAILABLE_IOS(7_0); // start time and duration are values between 0.0 and 1.0 specifying time and duration relative to the overall time of the keyframe animation

@end

代码示例:

-(void)menuClick:(UIButton *)btn{
    
    CGRect rect = CGRectMake(ScreenWidth/3-50, 275,0,0);

    if (open) {
        
        [UIView animateKeyframesWithDuration:duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
            
            for (int i=0; i<iconArr.count; i++) {
                
                [UIView addKeyframeWithRelativeStartTime:i*1.0/iconArr.count relativeDuration:1.0/iconArr.count animations:^{
                    
                    UIImageView * functionBtn = (UIImageView *)[self.view viewWithTag:100+i];
                    
                    functionBtn.frame = rect;
                    
                }];
                
            }
            
            open = NO;
            
        } completion:nil];
        
    }
    else{
        
        UIImage * icon1 = [UIImage imageNamed:@"functionIcon1"];
        
        CGRect rect1 = CGRectMake(ScreenWidth/3, 130,50,50);
        
        CGRect rect2 = CGRectMake(ScreenWidth/3+80, 210,50,50);
        
        CGRect rect3 = CGRectMake(ScreenWidth/3+80, 290,50,50);
        
        CGRect rect4 = CGRectMake(ScreenWidth/3, 370,50,50);
        
        iconArr = @[icon1,icon1,icon1,icon1];
        
        NSArray * rectArr = @[[NSValue valueWithCGRect:rect1],[NSValue valueWithCGRect:rect2],[NSValue valueWithCGRect:rect3],[NSValue valueWithCGRect:rect4]];
        
        for (int i=0; i<4; i++) {
            
            UIImageView * functionBtn = (UIImageView *)[self.view viewWithTag:100+i];
            
            if (!functionBtn) {
                
                functionBtn = [[UIImageView alloc]initWithImage:[iconArr objectAtIndex:i]];
                
                functionBtn.tag = 100+i;
                
                functionBtn.frame = rect;
                
                [self.view addSubview:functionBtn];
            }
            
        }
        
        
        [UIView animateKeyframesWithDuration:duration delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
            
            for (int i=0; i<iconArr.count; i++) {
                
                [UIView addKeyframeWithRelativeStartTime:i*1.0/iconArr.count relativeDuration:1.0/iconArr.count animations:^{
                    
                    UIImageView * functionBtn = (UIImageView *)[self.view viewWithTag:100+i];
                    
                    functionBtn.frame = [[rectArr objectAtIndex:i] CGRectValue];
                    
                }];
                
                
            }
        
            open = YES;

        } completion:nil];
        
    }

}
    

运行效果:

UIView关键帧.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • UIKit直接将动画集成到UIView类中,当内部的一些属性发生改变时,UIView将为这些改变提供动画支持。 U...
    白水灬煮一切阅读 1,386评论 0 0
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,439评论 6 30
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,083评论 5 13
  • 前言: UIVIew Animation 是 iOS 提供的最基础的一组用于实现 UIView 动画的类库。在 U...
    谢谢生活阅读 3,263评论 0 5
  • 先看看CAAnimation动画的继承结构 CAAnimation{ CAPropertyAnimation { ...
    时间不会倒着走阅读 1,633评论 0 1