Detailed explanation of iOS Animation
This article only explains the use of animation in iOS.
Animation is mainly divided into two categories: UIView animation and CoreAnimation animation.
UIView animation includes UIView property animation, UIViewBlock animation, and UIViewTransition animation.
CoreAnimation animation mainly passes CAAnimation and CALayer, commonly used ones are CABasicAnimation, CAKeyframeAnimation, CATransition, CAAnimationGroup.
Inherited from: UIResponder: NSObject
Follows: UITraitEnvironment, UIDynamicItem, NSObject, UICoordinateSpace, UIAppearanceContainer, UIAppearance, NSCoding
Framework: iOS 2.0 and later versions of UIKit
Because the View object is the main way for the application to interact with the user Pathways, they have a series of responsibilities. Listed below are some:
View can be embedded into other Views to create complex visual hierarchies. This creates a parent-child relationship between the embedded View (child View) and the embedded View (parent View). Under normal circumstances, the visible area of the child View will not be clipped by the bounds of the parent View, but in iOS you can use the clipsToBounds property to modify this behavior. A parent View may have multiple child Views, but a child View has only one parent View, which is responsible for determining the position of the child View.
The geometry of a View is defined through its frame, bounds, and center properties. The frame defines the origin and size of the View relative to the coordinate system of the parent View. It is generally used when laying out the View and adjusting its size or position. The center attribute can adjust the position of the view without changing the size of the view. bounds defines the internal dimensions of the view and is almost only used when customizing drawing code. The size part of the frame and the bounds rectangular part are coupled together, so you can use one or both of them at the same time to change the size of the view.
Use code to create a View:
swift:
let viewRect = CGRect(x: 10, y: 10, width: 100, height: 100)let myView = UIView(frame: viewRect)
Objective-c
CGRect viewRect = CGRectMake(10, 10, 100, 100);UIView* myView = [[UIView alloc] initWithFrame:viewRect];
This code creates the view and places it at point (10,10) in the parent view's coordinate system (once it is added to the parent view). To add a subview to another view, use the addSubview: method. In iOS, views at the same level can overlap each other without any problems, allowing complex view layouts. addSubview places the specified view on top of its sibling views. You can specify the relative z-coordinate of the subview using the insertSubview:aboveSubview: and insertSubview:belowSubview: methods. You can also use the exchangeSubviewAtIndex:withSubviewAtIndex: method to exchange the position of the added subview.
View painting happens when needed. When a view is first displayed, or when all or part of it becomes visible during a layout change, the system asks the view to draw its contents. For views that use UIKit or Core Graphics to contain custom content, the system calls its drawRect: method. Your implementation of this method is responsible for drawing the content of the view into the current graphics context, and the system automatically calls this method first. This creates a static visual representation of the view content, which is then displayed on the screen.
When the actual content of the view changes, it is your responsibility to notify the system that your view needs to be redrawn. Notify by calling the setNeedsDisplay or setNeedsDisplayInRect: method of the view. These methods let the system know that it should update the View during the next paint cycle. Because it waits until the next paint cycle to update the View, you can call these methods on multiple views and update them simultaneously.
Changing multiple View properties can be animated. In a short period of time, changing properties can create animations. The UIView class does a lot of the work of performing animations, but you still have to decide which property changes you want to be animated. The following are two different initialization animation methods:
Block-based animation methods (like animateWithDuration:animations:) greatly simplify animation creation. Just call a method, specify the animation parameters, and execute the animation. However, block-based animations are only available in iOS4 and later. If your device is running an older version of iOS, you must use the beginAnimations:context: and commitAnimations class methods to mark the start and end of animations.
The following are animation properties:
Thread Notes
Manipulating the user interface must occur on the main thread. Therefore, you must call methods of the UIView class on the main thread of your application. Only when creating the view object itself does not need to be strictly adhered to, but other operations must be in the main thread.
For visible content that also requires user interaction, the UIView class is a key subclassing point. Although there are many good reasons to extend UIView, we only recommend extending UIView when the basic UIView and other components that come with the system do not meet your needs. Inheriting UIView will consume more performance in the code you implement. (Apple writes code than Yours is better, use the ready-made ones if they are available).
When subclassing UIView, there are only a few methods you must override, and most you can override as needed. Because UIView is a highly configurable class, there are many ways to implement complex behavior without overriding parent class methods, which are covered in the Choosing Subclassing section. You may consider overriding the methods in the following list in your UIView subclass:
Many view behaviors can be configured without subclassing. As you start overriding these methods, consider whether the properties or behavior below can be modified to provide the functionality you need.
动画是不需要子类化和实现复杂代码而让视觉改变的另一种方式。很多UIView的属性是可以动画的,意味着改变这些属性可以触发系统生成动画。启动动画只需要很少的一行代码指示那些改变需要被动画。更多view动画的信息,参考Animations.
CGRect viewRect = CGRectMake(10,10,200,200);self.myView= [[UIView alloc] initWithFrame:viewRect];self.myView.backgroundColor = [UIColor whiteColor];[self.view addSubview:self.myView];//1 准备动画//参数1: 动画的作用, 任意字符串,用来区分多个动画, 参数二: 传递参数用 nil:OC中使用[UIView beginAnimations:@"changeSizeAndColor" context:nil];//在准备动画的时候可以设置动画的属性[UIView setAnimationDuration:0.7];[UIView setAnimationDelegate:self];[UIView setAnimationWillStartSelector:@selector(startAnimation)];[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];//动画的曲线[UIView setAnimationRepeatCount:2];[UIView setAnimationRepeatAutoreverses:YES];//动画往返执行, 必须设置动画的重复次数//2 修改view的属性, 可以同时修改多个属性 注意:不是所有的属性都可以修改的(只有frame, center, bounds, backgroundColor, alpha, transform 可以修改)self.myView.frame = CGRectMake(110, 100, 100, 100);self.myView.backgroundColor = [UIColor colorWithRed:arc4random() % 256 / 255.0 green:arc4random() % 256 / 255.0 blue:arc4random() % 256 / 255.0 alpha:0.5];//3 提交并执行动画[UIView commitAnimations];
Block动画的实质是对UIView动画的封装
第一种
[UIView animateWithDuration:2 animations:^{ self.myView.backgroundColor = [UIColor orangeColor]; }];
第二种
[UIView animateWithDuration:2 animations:^{ self.myView.backgroundColor = [UIColor orangeColor]; } completion:^(BOOL finished) { //finished判断动画是否完成 if (finished) { NSLog(@"finished"); } }];
第三种
[UIView animateWithDuration:2 delay:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{ // 设置要修改的View属性 self.myView.backgroundColor = [UIColor orangeColor]; } completion:^(BOOL finished) { //finished判断动画是否完成 if (finished) { NSLog(@"finished"); } }];
下面是AnimationOptionCurve参数:
UIViewAnimationOptionCurveEaseInOut = 0 << 16, // default UIViewAnimationOptionCurveEaseIn = 1 << 16, UIViewAnimationOptionCurveEaseOut = 2 << 16, UIViewAnimationOptionCurveLinear = 3 << 16,
[UIView transitionWithView:self.myView duration:2 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{ self.myView.backgroundColor = [UIColor orangeColor]; } completion:^(BOOL finished) { //finished判断动画是否完成 if (finished) { NSLog(@"finished"); } }];
下面是AnimationOptionTransition参数:
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,
Core Animation是一组非常强大的动画处理API,使用它能做出非常绚丽的动画效果,而且往往是事半功倍,使用它需要添加QuartzCore .framework和引入对应的框架
CABasicAnimation基本动画没有真正的修改属性值
初始化UIView的layer
CGRect viewRect = CGRectMake(50,100,200,200); self.myView= [[UIView alloc] initWithFrame:viewRect]; self.myView.backgroundColor = [UIColor whiteColor]; self.myView.layer.cornerRadius = 100;//设置圆角, 参数是内切圆的半径, 若想画一个圆, 前提是view必须是正方形, 参数应该是view边长的一半 self.myView.layer.borderWidth = 5;//设置描边的宽度 self.myView.layer.borderColor = [UIColor orangeColor].CGColor;//设置描边的颜色(UIView上的颜色使用的是UIColor, CALayer上使用的颜色是CGColor) self.myView.layer.shadowOffset = CGSizeMake(50, 100);//设置阴影的偏移量 width影响水平偏移(正右负左), height影响垂直偏移(正下负上) self.myView.layer.shadowColor = [UIColor redColor].CGColor;//阴影的偏移的颜色 self.myView.layer.shadowOpacity = 0.5;//阴影的不透明度, 取值范围(0 ~ 1), 默认是0, 就是透明的 [self.view addSubview:self.myView];
动画方法:
//1 创建并指定要修改的属性 // KeyPath:CAlayer的属性名, 不是所有的属性都可以, 只有在头文件中出现animatable的属性才可以, 可以修改属性的属性, 例如:bounds.size CABasicAnimation *basic = [CABasicAnimation animationWithKeyPath:@"bounds"]; [basic setDuration:0.7]; //2 修改属性值 basic.fromValue = [NSValue valueWithCGRect:CGRectMake(0, 0, self.myView.bounds.size.width, self.myView.bounds.size.height)]; basic.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 300, 300)]; //3 添加动画 //key做区分动画用 [self.myView.layer addAnimation:basic forKey:@"changColor"];
示例1,和上面的动画一样
//1 创建动画 CAKeyframeAnimation *keyFrame = [CAKeyframeAnimation animationWithKeyPath:@"bounds"]; [keyFrame setDuration:2]; //2 修改属性 keyFrame.values = @[[NSValue valueWithCGRect:CGRectMake(0, 0, self.myView.bounds.size.width, self.myView.bounds.size.height)], [NSValue valueWithCGRect:CGRectMake(0, 0, 250, 250)], [NSValue valueWithCGRect:CGRectMake(0, 0, 300, 300)]]; //keyTimes:值代表了出现动画的时刻, 值得范围是0~1, 值必须是递增的, keyTimes和values是一一对应的 keyFrame.keyTimes = @[@(0.4), @(0.6), @(1)]; //3 添加动画 [self.myView.layer addAnimation:keyFrame forKey:@"keyFrame"];
示例2,改变颜色
CAKeyframeAnimation *keyFrame = [CAKeyframeAnimation animationWithKeyPath:@"backgroundColor"]; [keyFrame setDuration:3]; keyFrame.values = @[(id)[UIColor redColor].CGColor, (id)[UIColor orangeColor].CGColor, (id)[UIColor yellowColor].CGColor, (id)[UIColor greenColor].CGColor, (id)[UIColor blueColor].CGColor]; keyFrame.keyTimes = @[@(0.3), @(0.5), @(0.6), @(0.7), @(0.9)]; [self.myView.layer addAnimation:keyFrame forKey:nil];
//1 创建 CATransition *transition = [CATransition animation]; [transition setDuration:2]; //2 设置过度样式 transition.type = kCATransitionReveal;//控制样式 transition.subtype = kCATransitionFromTop;//控制方向 //添加动画 [self.myView.layer addAnimation:transition forKey:nil];
//1 创建并指定要修改的属性 // KeyPath:CAlayer的属性名, 不是所有的属性都可以, 只有在头文件中出现animatable的属性才可以, 可以修改属性的属性, 例如:bounds.size // CALayer CABasicAnimation *basic = [CABasicAnimation animationWithKeyPath:@"bounds"]; [basic setDuration:2]; //2 修改属性值 basic.fromValue = [NSValue valueWithCGRect:CGRectMake(0, 0, self.myView.bounds.size.width, self.myView.bounds.size.height)]; basic.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 300, 300)]; CAKeyframeAnimation *keyFrame = [CAKeyframeAnimation animationWithKeyPath:@"backgroundColor"]; [keyFrame setDuration:2]; keyFrame.values = @[(id)[UIColor redColor].CGColor, (id)[UIColor orangeColor].CGColor, (id)[UIColor yellowColor].CGColor, (id)[UIColor greenColor].CGColor, (id)[UIColor blueColor].CGColor]; //keyTimes中的第一个值是0, 不能修改 keyFrame.keyTimes = @[@(0.3), @(0.5), @(0.6), @(0.7), @(0.9)]; // 创建 //当group动画的时长 > 组中所有动画的最长时长, 动画的时长以组中最长的时长为准 //当group动画的时长 < 组中所有动画的最长时长, 动画的时长以group的时长为准 //最合适: group的时长 = 组中所有动画的最长时长 CAAnimationGroup *group = [CAAnimationGroup animation]; [group setDuration:10]; //设置组动画 group.animations = @[basic, keyFrame]; //添加动画 [self.myView.layer addAnimation:group forKey:nil];
所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用它具体的子类.
属性解析:
duration:动画的持续时间 .repeatCount:动画的重复次数 .repeatDuration:动画的重复时间 .removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards .fillMode:决定当前对象在非active时间段的行为.比如动画开始之前,动画结束之后 .beginTime:可以用来设置动画延迟执行时间,若想延迟2s,就设置为CACurrentMediaTime()+2, CACurrentMediaTime()为图层的当前时间 .timingFunction:速度控制函数,控制动画运行的节奏 .delegate:动画代理
速度控制函数(CAMediaTimingFunction)
1. kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感觉2. kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加速离开3. kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地4. kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。 这个是默认的动画行为。
CAAnimation在分类中定义了代理方法
@interface NSObject <CAAnimationDelegate>- (void)animationDidStart:(CAAnimation *)anim;- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;@end
fillMode属性值(要想fillMode有效,最好设置removedOnCompletion=NO)
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态?.
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态.
?kCAFillModeBackwards 在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始. 你可以这样设定测试代码,将一个动画加入一个layer的时候延迟5秒执行.然后就会发现在动画没有开始的时候,只要动画被加入了layer,layer便处于动画初始状态 ?
kCAFillModeBoth 这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状
CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使用它的两个子类:CABasicAnimation和CAKeyframeAnimation.
属性解析:
keyPath:
通过指定CALayer的一个属性名称为keyPath(NSString类型),并且对CALayer的这个属性的值进行修改,达到相应的动画效果。比如,指定@”position”为keyPath,就修改CALayer的position属性的值,以达到平移的动画效果
CABasicAnimation
CAPropertyAnimation的子类 .
属性解析:
fromValue:keyPath相应属性的初始值 .toValue:keyPath相应属性的结束值 .随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue .
如果fillMode=kCAFillModeForwards和removedOnComletion=NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。比如,CALayer的position初始值为(0,0),CABasicAnimation的fromValue为(10,10),toValue为(100,100),虽然动画执行完毕后图层保持在(100,100)这个位置,实质上图层的position还是为(0,0)
//平移动画CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];// 动画持续1秒anim.duration =1; //因为CGPoint是结构体,所以用NSValue包装成一个OC对象anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(50, 50)];anim.toValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];//通过MyAnim可以取回相应的动画对象,比如用来中途取消动画[layer addAnimation:anim forKey:@"MyAnim"];//缩放动画CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];//没有设置fromValue说明当前状态作为初始值//宽度(width)变为原来的2倍,高度(height)变为原来的1.5倍anim.toValue = [NSValuevalueWithCATransform3D:CATransform3DMakeScale(2, 1.5, 1)];anim.duration = 1;[layer addAnimation:anim forKey:nil];//旋转动画CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];//这里是以向量(1, 1, 0)为轴,旋转π/2弧度(90°)//如果只是在手机平面上旋转,就设置向量为(0, 0, 1),即Z轴anim.toValue = [NSValuevalueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 1, 1, 0)];anim.duration = 1;[layer addAnimation:anim forKey:nil];
CApropertyAnimation的子类,跟CABasicAnimation的区别是:
CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值 .
属性解析:
values:就是上述的NSArray对象。里面的元素称为”关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧 .path:可以设置一个CGPathRef\CGMutablePathRef,让层跟着路径移动。path只对CALayer的anchorPoint和position起作用。如果你设置了path,那么values将被忽略 .keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的 .CABasicAnimation可看做是最多只有2个关键帧的CAKeyframeAnimation在关键帧动画中还有一个非常重要的参数,那便是calculationMode,计算模式.其主要针对的是每一帧的内容为一个座标点的情况,也就是对anchorPoint 和 position 进行的动画.当在平面座标系中有多个离散的点的时候,可以是离散的,也可以直线相连后进行插值计算,也可以使用圆滑的曲线将他们相连后进行插值计算. calculationMode目前提供如下几种模式:kCAAnimationLinear calculationMode的默认值,表示当关键帧为座标点的时候,关键帧之间直接直线相连进行插值计算;
?kCAAnimationDiscrete 离散的,就是不进行插值计算,所有关键帧直接逐个进行显示;
?kCAAnimationPaced 使得动画均匀进行,而不是按keyTimes设置的或者按关键帧平分时间,此时keyTimes和timingFunctions无效;
?kCAAnimationCubic 对关键帧为座标点的关键帧进行圆滑曲线相连后插值计算,这里的主要目的是使得运行的轨迹变得圆滑;
kCAAnimationCubicPaced 看这个名字就知道和kCAAnimationCubic有一定联系,其实就是在kCAAnimationCubic的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时keyTimes以及timingFunctions也是无效的.
CAAnimationGroup
CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行.
属性解析:
animations:用来保存一组动画对象的NSArray.默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间.
CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果。iOS比Mac OS X的转场动画效果少一点.
UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果.
属性解析:
type:动画过渡类型subtype:动画过渡方向startProgress:动画起点(在整体动画的百分比)endProgress:动画终点(在整体动画的百分比)
/* 过渡效果 fade //交叉淡化过渡(不支持过渡方向) kCATransitionFade push //新视图把旧视图推出去 kCATransitionPush moveIn //新视图移到旧视图上面 kCATransitionMoveIn reveal //将旧视图移开,显示下面的新视图 kCATransitionReveal cube //立方体翻滚效果 oglFlip //上下左右翻转效果 suckEffect //收缩效果,如一块布被抽走(不支持过渡方向) rippleEffect //滴水效果(不支持过渡方向) pageCurl //向上翻页效果 pageUnCurl //向下翻页效果 cameraIrisHollowOpen //相机镜头打开效果(不支持过渡方向) cameraIrisHollowClose //相机镜头关上效果(不支持过渡方向) */ /* 过渡方向 kCATransitionFromRight kCATransitionFromLeft kCATransitionFromBottom kCATransitionFromTop */// CATransition的使用 CATransition *anim = [CATransition animation];anim.type = @"cube"; // 动画过渡类型anim.subtype = kCATransitionFromTop; // 动画过渡方向anim.duration = 1; // 动画持续1s// 代理,动画执行完毕后会调用delegate的animationDidStop:finished:anim.delegate = self;
另外还有 UIImageView的帧动画 和 UIActivityIndicatorView,这里就暂不介绍了。
参考文档
http://www.pocketdigi.com/20150105/1413.html
版权声明:本文为博主原创文章,未经博主允许不得转载。