IOS core animation Advanced Skills-core animation (III) and ios core animation skills
Advanced iOS animation skills-CALayer (1)
Layer conversion and dedicated layer for iOS core animation (2)
IOS core animation Advanced Skills-core animation (III)
Performance of iOS core animation advanced skills (4)
IOS core Animation: animation Summary (5)
Implicit Animation
Implicit animation mainly applies to the animated attributes of CALayer. The layer corresponding to the UIView is not allowed. As long as you change the attribute value, it does not suddenly change directly, it is an animation process. You can control the time and other attributes through a transaction (CATransaction). If you do not provide a transaction yourself, the default time is 0.25 seconds, of course, this animation property needs to be triggered. If you set a value as soon as it comes up, you may not be able to see the animation effect.
1 redLayer = CALayer() 2 redLayer.backgroundColor = UIColor.redColor().CGColor 3 redLayer.frame = CGRectMake(50, 100, 100, 100) 4 self.view.layer.addSublayer(redLayer) 5 6 NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: NSSelectorFromString("animate"), userInfo: nil, repeats: false) 7 8 func animate() { 9 CATransaction.begin()10 CATransaction.setAnimationDuration(12)11 12 var redC = CGFloat(arc4random() % 256 ) / 255.013 var greenC = CGFloat(arc4random() % 256 ) / 255.014 var blueC = CGFloat(arc4random() % 256 ) / 255.015 16 self.redLayer.backgroundColor = UIColor(red: redC, green: greenC, blue: blueC, alpha: 1).CGColor17 18 CATransaction.commit()19 }
In the preceding transaction, you can add a completion block so that it can make a default animation of 0.25 seconds after the animation is completed. There are two animation modes in the demo (2d and 3d)
1 CATransaction. begin () 2 CATransaction. setAnimationDuration (3) 3 CATransaction. setCompletionBlock {()-> Void in 4/* 3d animation 5 var transform = self. redLayer. transform 6 transform = CATransform3DRotate (transform, CGFloat (M_PI_4), 0, 0, 1) 7 self. redLayer. transform = transform 8 */9 // This is a 2d animation 10 var transform = self. redLayer. affineTransform () 11 transform = CGAffineTransformRotate (transform, CGFloat (M_PI_4) 12 self. redLayer. setAffineTransform (transform)
The reason why a layer can be implicitly animated is that the corresponding attribute has a corresponding action. This action can be obtained through the layer's delegate proxy method actionforLayer: forkey, or by setting the layer's actions attribute, both methods do not have implicit animation for UIView because the delegate corresponding to the layer is its own, and its actionforlayer: forkey method returns nil each time, therefore, it does not have the corresponding action, so it cannot be used for implicit animation. If you want a view to have an implicit animation, you can rewrite its actionforlayer method and return an action with its corresponding key, the type of this action is CAtransition. in addition, the actionfoylayer method of the beginAnimations and commitAnimations methods in UIView can return values for implicit animation. If you do not want a normal layer to do implicit animation, you can call the setDisableActions method of CATransaction to disable it, setting actions to nil does not respond.
1 var transition = CATransition () 2 transition. type = kCATransitionPush // set the display mode. The default value is fade3 transition. subtype = kCATransitionFromLeft // set the direction to 4 redLayer. actions = ["backgroundColor": transition]
Layer can be used for implicit animation, but you can get the animation property and its value is still the final value, because it is not a layer-generated animation, it has a modelLayer that generally returns the layer itself. It also has a presenttationLayer that presents the layer. The value we set is for the modelLayer, And the animation is for the presentationLayer. there are two situations where you may need to use the rendering layer. One is that you need to obtain the position of the layer during the animation process, and the other is that you need to respond to user interaction during the animation process. the demo below shows that if you click the square, the color will change. If you click the square, the square will be moved to the position you clicked.
1 redLayer = CALayer() 2 redLayer.backgroundColor = UIColor.redColor().CGColor 3 redLayer.frame = CGRectMake(50, 100, 100, 100) 4 self.view.layer.addSublayer(redLayer) 5 6 override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) { 7 var point = ( touches as NSSet ) .anyObject()?.locationInView(self.view) 8 9 if (self.redLayer.presentationLayer().hitTest(point!) != nil) {10 var redC = CGFloat(arc4random() % 256 ) / 255.011 var greenC = CGFloat(arc4random() % 256 ) / 255.012 var blueC = CGFloat(arc4random() % 256 ) / 255.013 14 self.redLayer.backgroundColor = UIColor(red: redC, green: greenC, blue: blueC, alpha: 1).CGColor15 }else {16 CATransaction.begin()17 CATransaction.setAnimationDuration(2.0)18 self.redLayer.position = point!19 CATransaction.commit()20 }21 }
Explicit Animation
CABasicAnimation (property animation)
The CABasicAnimation animation is similar to the implicit animation, which can set the start and end values and delegate. The following example is similar to the preceding implicit animation.
1 redLayer = CALayer () 2 redLayer. backgroundColor = UIColor. redColor (). CGColor 3 redLayer. frame = CGRectMake (50,100,100,100) 4 self. view. layer. addSublayer (redLayer) 5 6 nstlayer. scheduledTimerWithTimeInterval (1, target: self, selector: NSSelectorFromString ("animate"), userInfo: nil, repeats: false) 7} 8 9 func animate () {10 var redC = CGFloat (arc4random () % 256)/255.011 var greenC = CGFloat (Arc4random () % 256)/255.012 var blueC = CGFloat (arc4random () % 256)/255.013 var color = UIColor (red: redC, green: greenC, blue: blueC, alpha: 1 ). CGColor14 15 var animate = CABasicAnimation () 16 animate. duration = 8.017 animate. keyPath = "backgroundColor" 18 animate. toValue = color19 animate. delegate = self20 self. redLayer. addAnimation (animate, forKey: nil) 21} 22 23 override func animationDidS Top (anim: CAAnimation !, Finished flag: Bool) {24 CATransaction. begin () 25 26 CATransaction. setDisableActions (true) 27 var animate = anim! CABasicAnimation28 self. redLayer. backgroundColor = animate. toValue! CGColorRef29 CATransaction. commit () 30}View Code
Note: In the code, the implicit animation in the stop proxy method is disabled. Otherwise, it will be animated twice. It is not required if it is a view layer animation, this is because the implicit animation of view is disabled by default. If multiple animations require a proxy method, you can set the key when adding the animation and obtain the animation through the key in the proxy method. there is also a simpler KVC to get, animate. setValue (redView, forKey: "redView"), which is obtained using valueForKey in the proxy method.
CAKeyframeAnimation (Key Frame Animation)
The Key Frame Animation is known and known. You set the value of each frame in the values attribute, and then iOS will perform the animation based on the value you set. You can also set the corresponding time for the animation, this is very powerful. Now we will talk about another powerful function, which can be used for animation along the path. You just need to set a CGBezierPathRef value with its path attribute. in fact, the animation along the path is the same as setting values. The path is also composed of position points. The animation along the path requires the object to follow the path to adjust the direction, you can perform rotate animation in the same direction as it, but it may cause conflicts or other problems. You can set rotationMode to rotateAuto. the demo is simple.
Note that transform is used for transform animation. rotation and so on will be much better, on the one hand you can use byValue to set the value, on the other hand, position/scale/rotation will not conflict. you directly set transform. the position value is actually useless, because it does not have this attribute, but in iOS, it uses KVC to transform. the position value is converted to the matrix value corresponding to transform using CAValueFuction.
CAAnimationGroup (Group Animation)
CAAnimationGroup can also be used as an animation group as its name implies. You only need to set an animation array with its animations attribute. The value of each array item is either basicAnimation or keyframeAnimation.
CATransition (transition animation)
The first thing to note here is that CATransition is an animation, while CATransaction is an animation transaction, both of which are two concepts in the core animation. it should be said that CATransition is the simplest and best-to-use but most easily overlooked animation in the core animation. The following shows how simple it is to give an fadein animation when setting an image in imageview.
1 NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: NSSelectorFromString("animate"), userInfo: nil, repeats: false) 2 3 self.img = UIImageView(image: UIImage(named: "111.png")) 4 self.view.addSubview(self.img) 5 } 6 7 func animate () { 8 var transition = CATransition() 9 transition.type = kCATransitionFade10 self.img.layer .addAnimation(transition, forKey: nil)11 12 self.img.image = UIImage(named: "222.png")13 }
For CAtransition, it is added by default in the self-created layer, and it is disabled in the view-associated tu city, after all, it still has to provide you with a simple and normal way to set attributes. It is effective for the entire layer tree. If transition is added, it will add the entire effect to its child layers, for example, the gradient effect of switching with tabbar (most VC switches can write animations in the proxy method or other methods)
1 var root = UITabBarController() 2 root.viewControllers = [ViewController(),OneViewController()] 3 root.delegate = self 4 self.rootVC = root 5 6 self.window?.rootViewController = root 7 self.window?.makeKeyAndVisible() 8 9 return true10 }11 func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) {12 var transition = CATransition()13 transition.type = kCATransitionFade14 transition.duration = 315 self.rootVC.view.layer.addAnimation(transition, forKey: nil)16 }
UiView provides the transitionFromView method. If only one view is used as an animation, you can use it to have the same effect as the transition animation, but generally it does not work on the child layer, when an animation is running, you can remove the animation, add an animation with one button, and delete the animation with one button. The animation uses byValue, so the effect is paused.
The following code pauses an animation and updates the value of the model tree as presentlayer during the pause.
1 redLayer = CALayer () 2 redLayer. backgroundColor = UIColor. redColor (). CGColor 3 redLayer. frame = CGRectMake (50,100,100,100) 4 self. view. layer. addSublayer (redLayer) 5 6 var beginBtn = UIButton (frame: CGRectMake (50,300,100, 30) 7 beginBtn. setTitle ("START", forState: UIControlState. normal) 8 beginBtn. addTarget (self, action: "begin", forControlEvents: UIControlEvents. touchUpInside) 9 self. view. addSubview (beginBtn) 10 11 var stopBtn = UIButton (frame: CGRectMake (200,300,100, 30) 12 stopBtn. setTitle ("pause", forState: UIControlState. normal) 13 stopBtn. addTarget (self, action: "stop", forControlEvents: UIControlEvents. touchUpInside) 14 self. view. addSubview (stopBtn) 15} 16 17 func begin () {18 var animate = CABasicAnimation () 19 animate. keyPath = "transform. rotation "20 animate. duration = 2.021 animate. byValue = CGFloat (M_PI/4) 22 animate. delegate = self23 // animate. fillMode = kCAFillModeForwards24 // animate. removedOnCompletion = false25 self. redLayer. addAnimation (animate, forKey: "animate") 26} 27 func stop () {28 self. redLayer. transform = self. redLayer. presentationLayer (). transform29 self. redLayer. removeAnimationForKey ("animate") 30}View Code
Layer time
The three animation attributes beginTime/speed/timeoffset are relative concepts, indicating the start time of the corresponding duration and the animation speed (changing the animation end time ), allows an animation to quickly enter a certain point. the following is the second method for pausing an animation.
1 redLayer = CALayer () 2 redLayer. backgroundColor = UIColor. redColor (). CGColor 3 redLayer. frame = CGRectMake (50,100,100,100) 4 self. view. layer. addSublayer (redLayer) 5 6 var beginBtn = UIButton (frame: CGRectMake (50,300,100, 30) 7 beginBtn. setTitle ("START", forState: UIControlState. normal) 8 beginBtn. addTarget (self, action: "resumeLayer", forControlEvents: UIControlEvents. touchUpInside) 9 self. view. addSubview (beginBtn) 10 11 var stopBtn = UIButton (frame: CGRectMake (200,300,100, 30) 12 stopBtn. setTitle ("pause", forState: UIControlState. normal) 13 stopBtn. addTarget (self, action: "pauseLayer", forControlEvents: UIControlEvents. touchUpInside) 14 self. view. addSubview (stopBtn) 15 16 self. pauseTime = 0.017 self. startAnimate () 18} 19 20 func startAnimate () {21 var animate = CABasicAnimation () 22 animate. keyPath = "transform. rotation "23 animate. duration = 20.024 animate. byValue = CGFloat (M_PI * 10) 25 animate. delegate = self26 self. redLayer. addAnimation (animate, forKey: "animate") 27} 28 29 func pauseLayer () {30 // get the current animation time 31 self. pauseTime = self. redLayer. convertTime (CACurrentMediaTime (), fromLayer: nil) 32 // stop motion 33 self. redLayer. speed = 0.034 // set it to remain in the current state, otherwise, because speed is 0, the layer changes back to the initial animation value 35 self. redLayer. timeOffset = self. pauseTime36} 37 38 func resumeLayer () {39 // get the pause start time 40 var pausedTime = self. pauseTime41 // set the speed, such as timeOffset, to a normal value of 42 self. redLayer. speed= 1.043 self. redLayer. timeOffset = 0.044 self. redLayer. beginTime = 0.045 46 var timeSincePause = self. redLayer. convertTime (CACurrentMediaTime (), fromLayer: nil)-pausedTime47 // set the start time to the time difference of 48 self. redLayer. beginTime = timeSincePause49}View Code
When removeOnCompletion is set to no, the state of the previous step will remain after the animation ends, and then the fillMode is set to modeforwards, so that the animation can be kept in the original interface after execution without returning to the initial value.
Animation speed
SetCAAnimation
OftimingFunction
Attributes can control the animation speed, whileCAKeyframeAnimation
There isNSArray
TypetimingFunctions
Attribute, which requires the length of the values array to be 1 higher than its length, so that the speed of each animation can be controlled. The value of timingFunction is of the CAMediaTimingFunction type. It also has an initialization method to customize the time curve. It is a three-time besell buffer function and can be initialized through the start point, end point, and two control points, the default value of CAMediaTimingFunction can be initialized in this way.
Set the length of the values array to 5 and the length of the timingFunctions array to 4, which is equivalent to four key frames. The time curve of each animation is controlled by each item of the timingFunction, the four animations share the during time. You can also set the keyTimes value. It is also an array, and it has the same length as the timingFunction array, control the time of each animation. You can use this feature to perform most rule animations.
Through the above method, we have basically been able to do any animation, but I need to set multiple values, timingFunction, and keytimes to make a spring effect or Ball Landing effect, in addition, accurate calculations are required, and the results are not realistic. Therefore, we can directly set the value of values to the animation path. because the time is average, and the value of values is different, the speed will eventually be different, it will produce brilliant results. The function of generating paths this website provides: http://www.timotheegroleau.com/Flash/experiments/easing_function_generator.htm
Timer
As we have mentioned above, we set a series of values and then perform the animation based on the same time interval. Since adding this key frame animation only allows it to motion a certain known distance within each same time, this can be solved directly with NSTime. Every time we traverse the value of the values array, we can let it shift to that. In fact, this is the essence of the core animation. It has a problem that NSTime is added to the nsunloop, while every thread in iOS manages a nsunloop, every time an event is added to the task list, the permission is relatively low. If a screen has a lot of animations, there may be latency, And then there may be a choppy phenomenon, animation is not smooth. You can also replace it with CADisplayLink. It works the same as NSTime. It only takes some time to execute a method and they can set their own priorities, the difference is that NSTime is added to the task list. It will be called once when the screen is refreshed. The screen refresh rate is usually 60 times per second, while NSTime is added to the task list, it will be blocked by other tasks, tasks in the main thread include processing touch events, sending and receiving network packets, executing code using gcd, processing timer behavior, and screen re-painting. The POP framework of FB also uses CADisplayLink.