Анимация изменения текста UILabel

Я хочу оживить изменения текста в UILabel.

Например: старый текст перемещается вверх и новый текст перемещается снизу.

Я уже понял, что мне нужны метки. Один для старого и один для нового текста. Второй UILabel расположен ниже первого. Затем оба оживляют.

Однако, как вы отрезаете первую метку, когда она оживляет предыдущую часть кадра?

Ответ 1

Используйте UIView Расширение

Вам не нужно несколько ярлыков. Вы можете анимировать на месте с помощью одной метки:
 - Использовать встроенные анимации CALayer и расширение UIView
 - В Раскадке поместите UILabel внутри UIView с флагом Clip Subviews (footnote).
 - pushTransition применим к большинству UIView

1. Расширение

// 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)
    }
}

Swift 2 и ранее (см. комментарий Стива Богмана): используйте self.layer.addAnimation(animation, forKey: kCATransitionPush)

2. pushTransition Вызов

if let aLabel = label {
    aLabel.pushTransition(0.4)
    aLabel.text = "\(count)"
    count += 1
}

3. В действии

Вы можете даже контролировать кривую, продолжительность и направление .

CALayer Animation


(†) Обрезание - важный шаг для желаемого эффекта.

► Найти это решение на GitHub и дополнительные сведения о Swift Рецепты.

Ответ 2

Objective-C

Быстрое расширение UIView можно решить в Objective-C с помощью Interface Extension.

1. 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 Вызов

[aLabel pushTransition:0.4];
aLabel.text = [[NSString alloc] initWithFormat:@"%ld", (long) ++self.count];

3. В действии

анимация UILabel


Одноразовый: без расширения интерфейса:

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"];

Призвание:

aLabel.text = [[NSString alloc] initWithFormat:@"%ld", (long) ++self.count];

Ответ 3

QuartzCore предоставляет класс CATransition для анимированных операций перехода. CATransition имеет следующее определение:

Класс CATransition реализует переходные анимации для слоя. Вы можете указать эффект перехода из набора предопределенных переходов или путем предоставления пользовательского экземпляра CIFilter.


Чтобы ваш анимированный текстовый переход с надписью, нажимая вверх старый текст, вам нужно создать экземпляр CATransition и установить его type на kCATransitionPush и его subtype на kCATransitionFromTop

let animation = CATransition()
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
animation.type = kCATransitionPush
animation.subtype = kCATransitionFromTop
animation.duration = 1

После этого вы сможете анимировать перенос текста ярлыка, добавив анимацию в слой метки:

label.layer.add(animation, forKey: nil)
label.text = "Some new content"

Следующий код Swift 3 Playground показывает возможную реализацию, чтобы анимировать текстовый переход UILabel, используя 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