UIView Animations
本文主要从下面五个方面进行介绍:
- 普通的UIView Animations
- Springs
- Transitions
- View Animations in Practice
- Keyframe Animations
Animatable properties:
- frame
- bounds
- center
- backgroundColor
- alpha
- transform
普通的UIView Animations
Declaration
SWIFT
class func animateWithDuration(_ duration: NSTimeInterval,
delay delay: NSTimeInterval,
options options: UIViewAnimationOptions,
animations animations: () -> Void,
completion completion: ((Bool) -> Void)?)
OBJECTIVE-C
- (void)animateWithDuration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
options:(UIViewAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion
参数名都很直白不一一解释,只着重讲一下options。
有很多options可供选择:
- UIViewAnimationOptionCurveEaseInOut
An ease-in ease-out curve causes the animation to begin slowly, accelerate through the middle of its duration, and then slow again before completing.
- UIViewAnimationOptionCurveEaseIn
An ease-in curve causes the animation to begin slowly, and then speed up as it progresses.
- UIViewAnimationOptionCurveEaseOut
An ease-out curve causes the animation to begin quickly, and then slow as it completes.
- UIViewAnimationOptionCurveLinear
A linear animation curve causes an animation to occur evenly over its duration.
- UIViewAnimationOptionRepeat
Repeat the animation indefinitely.
- UIViewAnimationOptionAutoreverse
Run the animation backwards and forwards. Must be combined with the UIViewAnimationOptionRepeat option.
Example:
label.textColor = UIColor.whiteColor()
label.alpha = 0.0
UIView.animateWithDuration(1.0, delay: 0.2, options: .CurveEaseInOut | .Repeat | .AutoReverse animations: {
label.textColor = UIColor.yellerColor()
label.alpha = 1.0
}, completion: {
})
上面例子,创造了推迟0.2秒启动的动画,动画持续时间是1.0秒。渐显label,并颜色从白到黄,达到一种闪烁的效果。因为options 设置了.Repeat, .AutoReverse。label会一直闪烁着。
Springs
Springs 可以简单理解成弹簧效果,如下图:
UIView.animateWithDuration(1.5, delay: 0.0, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.0, options: [], animations: {
self.loginButton.bounds.size.width += 80.0
}, completion: nil)
- usingSpringWithDamping: accept value from 0.0 to 1.0. Values closer to 0.0 create a bouncier animation, while values closer to 1.0 create a stiff-looking effect. You can think of this value as the “stiffness” of the spring.
-
initialSpringVelocity: This controls the initial velocity of the animation. A value of 1.0 sets the velocity of the animation to cover the total distance of the animation in the span of one second. Bigger and smaller values will cause the animation to have more or less velocity.
效果如下图:
UIView.animateWithDuration(0.33, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.0, options: [], animations: {
self.loginButton.center.y += 60.0
self.loginButton.backgroundColor = UIColor(red: 0.85, green: 0.83, blue: 0.45, alpha: 1.0)
self.spinner.center = CGPoint(x: 40.0, y: self.loginButton.frame.size.height/2)
self.spinner.alpha = 1.0
}, completion: nil)
Transitions
Transitions are predefined animations you can apply to views
the predefined transition animation options:
- TransitionFlipFromLeft
- TransitionFlipFromRight
- TransitionCurlUp
- TransitionCurlDown
- TransitionCrossDissolve
- TransitionFlipFromTop
- TransitionFlipFromBottom
+ transitionWithView:duration:options:animations:completion:
Creates a transition animation for the specified container view.
Discussion
This method applies a transition to the specified view so that you can make state changes to it. The block you specify in the animations parameter contains whatever state changes you want to make. You can use this block to add, remove, show, or hide subviews of the specified view. If you want to incorporate other animatable changes, you must include the UIViewAnimationOptionAllowAnimatedContent key in the options parameter.
Add a new view
UIView.transitionWithView(animationContainerView, duration: 0.33, options: .CurveEaseOut | .TransitionFlipFromBottom, animations {
self.animationContainerView.addSubview(newView)
}, completion: nil}
Removing a view
UIView.transitionWithView(animationContainerView, duration: 0.33, options: .CurveEaseOut | .TransitionFlipFromBottom, animations: {
self.newView.removeFromSuperview()
}, completion: nil)
Hiding/ showing a view
UIView.transitionWithView(self.newView, duration: 0.33, options: .CurveEaseOut | .TransitionFlipFromBottom, animations: {
self.newView.hidden = true
}, complection: nil)
Replacing a view with another view
[UIView transitionWithView:containerView
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
[fromView removeFromSuperview];
[containerView addSubview:toView];
}
completion:nil];
there a sampler way to implement it:
+ (void)transitionFromView:(UIView *)fromView
toView:(UIView *)toView
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)options
completion:(void (^)(BOOL finished))completion
Discussion
This method provides a simple way to transition from the view in the fromView parameter to the view in the toView parameter. By default, the view in fromView is replaced in the view hierarchy by the view in toView. If both views are already part of your view hierarchy, you can include the UIViewAnimationOptionShowHideTransitionViews option in the options parameter to simply hide or show them.
This method modifies the views in their view hierarchy only. It does not modify your application’s view controllers in any way. For example, if you use this method to change the root view displayed by a view controller, it is your responsibility to update the view controller appropriately to handle the change.
The view transition starts immediately unless another animation is already in-flight, in which case it starts immediately after the current animation finishes.
UIView.transitonFromView(self.oldView, toView: self.newView, duration: 0.2, options: .TransitionFlipFromTop, completion: nil)
To simply hide or show them:
UIView.transitionFromView(self.oldView, toView: self.newView, duration: 0.2, options: .ShowHideTransitionViews, completion:nil)
In Practice
Crossfading animations
func fadeImageView(imageView: UIImageView, toImage: UIImage, showEffects: Bool) {
UIView.transitionWithView(imageView, duration: 1.0, options: .TransitionCrossDissolve, animations: {
imageView.image = toImage
}, complection: nil)
UIView.animationWithDuration(1.0, delay: 0.9, options: .CurveEaseOut, animation: {
self.snowView.alpha = showEffects ? 1.0 : 0.0
}, completion: nil)
Cube transitions
func cubeTransition(label: UILabel, text: String, direction: AnimationDirection) {
let auxLabel = UILabel(frame: label.frame)
auxLabel.text = text
auxLabel.font = label.font
auxLabel.textAlignment = label.textAlignment
auxLabel.textColor = label.textColor
auxLabel.backgroundColor = UIColor.clearColor()
let auxLabelOffset = CGFloat(direction.rawValue) * label.frame.size.height / 2.0
auxLabel.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1.0, 0.1), CGAffineTransformMakeTranslation(0.0, auxLabelOffset))
label.superview!.addSubview(auxLabel)
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseOut, animations: {
auxLabel.transform = CGAffineTransformIdentity
label.transform = CGAffineTransformConcat(
CGAffineTransformMakeScale(1.0, 0.1),
CGAffineTransformMakeTranslation(0.0, -auxLabelOffset))
}, completion: { _ in
label.text = auxLabel.text
label.transform = CGAffineTransformIdentity
auxLabel.removeFromSuperview()
})
}
Fade and bounce transitions
func moveLabel(label: UILabel, text: String, offset: CGPoint) {
let auxLabel = UILabel(frame: label.frame)
auxLabel.text = text
auxLabel.font = label.font
auxLabel.textAlignment = label.textAlignment
auxLabel.textColor = label.textColor
auxLabel.backgroundColor = UIColor.clearColor()
auxLabel.transform = CGAffineTransformMakeTranslation(offset.x, offset.y)
auxLabel.alpha = 0.0
view.addSubview(auxLabel)
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseIn, animations: {
label.transform = CGAffineTransformMakeTranslation(offset.x, offset.y)
label.alpha = 0.0
}, completion: nil)
UIView.animateWithDuration(0.25, delay: 0.1, options: .CurveEaseIn, animations: {
auxLabel.transform = CGAffineTransformIdentity
auxLabel.alpha = 1.0
}, completion: { _ in
auxLabel.removeFromSuperview()
label.text = text
label.alpha = 1.0
label.transform = CGAffineTransformIdentity
})
}
Keyframe Animations
Declaration:
class func animateKeyframesWithDuration(_ duration: NSTimeInterval,
delay delay: NSTimeInterval,
options options: UIViewKeyframeAnimationOptions,
animations animations: () -> Void,
completion completion: ((Bool) -> Void)?)
OBJECTIVE-C
- (void)animateKeyframesWithDuration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
options:(UIViewKeyframeAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion
Discussion
This method creates an animation block that you can use to set up a keyframe-based animation. The keyframes themselves are not part of the initial animation block you create using this method. Inside the animations block, you must add the keyframe time and animation data by calling the addKeyframeWithRelativeStartTime:relativeDuration:animations: method one or more times. Adding keyframes causes the animation to animate the view from its current value to the value of the first keyframe, then to the value of the next keyframe, and so on at the times you specify.
If you do not add any keyframes in the animations block, the animation proceeds from start to end like a standard animation block. In other words, the system animates from the current view values to any new values over the specified duration.
let originalCenter = planeImage.center
UIView.animateKeyframesWithDuration(1.5, delay: 0.0, options: [], animations: {
//add keyframes
//
UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.25, animations: {
self.planeImage.center.x += 80.0
self.planeImage.center.y -= 10.0
})
UIView.addKeyframeWithRelativeStartTime(0.1, relativeDuration: 0.4) {
self.planeImage.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI_4/2))
}
UIView.addKeyframeWithRelativeStartTime(0.25, relativeDuration: 0.25) {
self.planeImage.center.x += 100.0
self.planeImage.center.y -= 50.0
self.planeImage.alpha = 0.0
}
UIView.addKeyframeWithRelativeStartTime(0.51, relativeDuration: 0.01) {
self.planeImage.transform = CGAffineTransformIdentity
self.planeImage.center = CGPoint(x: 0.0, y: originalCenter.y)
}
UIView.addKeyframeWithRelativeStartTime(0.55, relativeDuration: 0.45) {
self.planeImage.alpha = 1.0
self.planeImage.center = originalCenter
}
}, completion: nil)