I want to animate text changes in a UILabel.
For example: old text moves up and new text moves in from the bottom.
I already realised that I would need to labels. One for the old and one for the new text. The second UILabel
is located below the first. Then both animate up.
However, how do you cut off the first label as it animates past the top portion of the frame?
Use a UIView
Extension
Animate in place using a single label:
- Leverage upon the built-in CALayer
animations, and a UIView
extension
- In the Storyboard, place the UILabel
inside a UIView
with Clip Subviews flag † .
- pushTransition
is applicable to most UIView
1. Extension
// Usage: insert view.pushTransition right before changing content
extension UIView {
func pushTransition(_ duration:CFTimeInterval) {
let animation:CATransition = CATransition()
animation.timingFunction = CAMediaTimingFunction(name:
kCAMediaTimingFunctionEaseInEaseOut)
animation.type = kCATransitionPush
animation.subtype = kCATransitionFromTop
animation.duration = duration
layer.add(animation, forKey: kCATransitionPush)
}
}
2. Invocation
if let aLabel = label {
aLabel.pushTransition(0.4) // Invoke before changing content
aLabel.text = "\(count)"
count += 1
}
3. Example
Animation with a kCAMediaTimingFunctionEaseInEaseOut
curve, a 0.4
second duration, and a kCATransitionFromTop
direction † .
(†) Clipping is an important step for desired effect.
Swift 2 and earlier, see Steve Baughman 's comment:
self.layer.addAnimation(animation, forKey: kCATransitionPush)
► Find this solution on GitHub and additional details on Swift Recipes .
Objective-C
The Swift UIView Extension can be solved in Objective-C with an Interface Extension
.
1. The Interface Extension
@interface UIView (SO33632266)
- (void)pushTransition:(CFTimeInterval)duration;
@end
@implementation UIView (SO33632266)
// Usage: insert [view pushTransition:]; right before changing content
- (void)pushTransition:(CFTimeInterval)duration
{
CATransition *animation = [CATransition new];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.type = kCATransitionPush;
animation.subtype = kCATransitionFromTop;
animation.duration = duration;
[self.layer addAnimation:animation forKey:kCATransitionPush];
}
@end
2. pushTransition
Invocation
[aLabel pushTransition:0.4];
aLabel.text = [[NSString alloc] initWithFormat:@"%ld", (long) ++self.count];
3. In Action
One-off: without Interface Extension:
CATransition *animation = [CATransition animation];
animation.timingFunction = [CAMediaTimingFunction
functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.type = kCATransitionPush;
animation.subtype = kCATransitionFromTop;
animation.duration = 0.4;
[aLabel.layer addAnimation:animation forKey:@"kCATransitionPush"];
Invocation:
aLabel.text = [[NSString alloc] initWithFormat:@"%ld", (long) ++self.count];
QuartzCore provides a CATransition
class for animated transition operations. CATransition
has the following definition:
The
CATransition
class implements transition animations for a layer. You can specify the transition effect from a set of predefined transitions or by providing a customCIFilter
instance.
In order to have your label's text transition animated by pushing upwards the old text, you'll have to create an instance of CATransition
and set its type
to kCATransitionPush
and its subtype
to kCATransitionFromTop
:
let animation = CATransition()
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
animation.type = kCATransitionPush
animation.subtype = kCATransitionFromTop
animation.duration = 1
You will then be able to animate your label's text transition by adding the animation to your label's layer:
label.layer.add(animation, forKey: nil)
label.text = "Some new content"
The following Swift 3 Playground code shows a possible implementation in order to animate a UILabel
's text transition using CATransition
:
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
let label: UILabel = {
$0.frame.origin = CGPoint(x: 50, y: 50)
$0.text = "Bob"
$0.sizeToFit()
return $0
}(UILabel())
let animation: CATransition = {
$0.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
$0.type = kCATransitionPush
$0.subtype = kCATransitionFromTop
$0.duration = 1
return $0
}(CATransition())
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(label)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggle(_:)))
view.addGestureRecognizer(tapGesture)
}
func toggle(_ sender: UITapGestureRecognizer) {
label.layer.add(animation, forKey: nil)
label.text = label.text == "Bob" ? "Dan" : "Bob"
label.sizeToFit()
}
}
let controller = ViewController()
PlaygroundPage.current.liveView = controller
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.