UILabelでのテキスト変更のアニメーション


133

新しいテキスト値をに設定していUILabelます。現在、新しいテキストは問題なく表示されます。ただし、新しいテキストが表示されたときにアニメーションを追加したいと思います。新しいテキストの外観をアニメーション化するために何ができるか疑問に思っています。


Swift 5について、問題を解決する2つの異なる方法を示す私の回答を参照しください。
Imanou Petit

回答:


177

ちゃんと動くのかなぁ!

Objective-C

[UIView transitionWithView:self.label 
                  duration:0.25f 
                   options:UIViewAnimationOptionTransitionCrossDissolve 
                animations:^{

    self.label.text = rand() % 2 ? @"Nice nice!" : @"Well done!";

  } completion:nil];

スイフト3、4、5

UIView.transition(with: label,
              duration: 0.25,
               options: .transitionCrossDissolve,
            animations: { [weak self] in
                self?.label.text = (arc4random()() % 2 == 0) ? "One" : "Two"
         }, completion: nil)

16
TransitionCrossDissolveがこの作業の鍵であることに注意してください。
あかる2014年

7
UIViewアニメーションブロックに[weak self]は必要ありません。stackoverflow.com/a/27019834/511299を
Sunkas

162

Objective-C

達成するために、真のクロスディゾルブトランジションを(古いラベルがフェードアウトしながら、新しいラベルにフェージング)、あなたはフェード不可視にしたくありません。テキストが変更されていなくても不要なちらつきが発生します

代わりにこのアプローチを使用してください:

CATransition *animation = [CATransition animation];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.type = kCATransitionFade;
animation.duration = 0.75;
[aLabel.layer addAnimation:animation forKey:@"kCATransitionFade"];

// This will fade:
aLabel.text = "New"

また 、2つの数値間でUILabelテキストをアニメーション化しますか?

iOS 10、9、8でのデモ:

空白、1〜5のフェードトランジション


Xcode 8.2.1&7.1iOS 10〜8.0のObjectiveCでテスト済み。

►プロジェクト全体をダウンロードするには、Swift RecipesSO-3073520を検索してください。


2つのラベルを同時に設定すると、シミュレータでちらつきが発生します。
ハギー

1
おそらく誤用?私のアプローチのポイントは、2つのラベルを使用しないことです。単一のラベル-addAnimation:forKeyをそのラベルに使用し、ラベルのテキストを変更します。
SwiftArchitect 2014年

@ConfusedVorlon、ステートメントを確認してください。そして、swiftarchitect.com / recipes /#SO-3073520に投稿されたプロジェクトをチェックします。
SwiftArchitect 2015年

私は過去にこれに棒の間違った終わりを持っているかもしれません。レイヤーのトランジションを一度定義してから、その後変更を加えて「フリー」フェードを取得できると思いました。変更ごとにフェードを指定する必要があるようです。したがって、毎回トランジションを呼び出すと、iOS9での私のテストでこれは正常に機能します。
混乱しているVorlon、2015年

誤解を招く要素を削除してください。iOS9では適切ではないと思われる場合は機能しないようです。ありがとうございました。
SwiftArchitect 2015年

134

スウィフト4

UILabel(またはそのための任意のUIView)をフェードする適切な方法は、を使用することCore Animation Transitionです。これはちらつきが発生せず、コンテンツが変更されていない場合に黒にフェードしません。

ポータブルでクリーンなソリューションはExtension、Swiftでaを使用することです(以前に変更された表示要素を呼び出します)。

// Usage: insert view.fadeTransition right before changing content


extension UIView {
    func fadeTransition(_ duration:CFTimeInterval) {
        let animation = CATransition()
        animation.timingFunction = CAMediaTimingFunction(name:
            CAMediaTimingFunctionName.easeInEaseOut)
        animation.type = CATransitionType.fade
        animation.duration = duration
        layer.add(animation, forKey: CATransitionType.fade.rawValue)
    }
}

呼び出しは次のようになります。

// This will fade
aLabel.fadeTransition(0.4)
aLabel.text = "text"

空白、1〜5のフェードトランジション


この上のソリューションの検索► GitHubの上やその他の詳細スウィフトのレシピを


1
こんにちは私はあなたが興味があるかもしれないと思った私のプロジェクトであなたのコードを使用しました:github.com/goktugyil/CozyLoadingActivity
Esqarrouth

ニース-MITライセンス(同じライセンスの弁護士トークバージョン)を使用できれば、商用アプリで使用できます...
SwiftArchitect

ライセンスについてはよくわかりません。現在、人々が商用アプリでそれを使用するのを妨げているものは何ですか?
Esqarrouth 2015年

2
多くの企業がに記載されている場合を除き、標準のライセンス使用することはできませんopensource.org/licensesをし、いくつかは、のみに付着Cocoapodsを組み込む予定opensource.org/licenses/MIT。そのMITライセンスは、Cocoapodが誰でも、誰でも自由に使用できることを保証します。
SwiftArchitect 2015

2
現在のWTFライセンスの問題は、それがあなたの根拠をカバーしていないことです:まず第一に、それはあなたを著者(著作権)として主張せず、そのため、あなたが特権を与えることができないことを証明します。MITライセンスでは、最初に所有権を主張し、次にそれを使用して権利を放棄します。プロにコードを活用してもらい、オープンソースの取り組みに参加してもらいたい場合は、MITをよく読んでください。
SwiftArchitect 2015

20

iOS4以来、それは明らかにブロックで行うことができます:

[UIView animateWithDuration:1.0
                 animations:^{
                     label.alpha = 0.0f;
                     label.text = newText;
                     label.alpha = 1.0f;
                 }];

11
クロスフェード遷移ではありません。
SwiftArchitect 2014

17

これを機能させるコードは次のとおりです。

[UIView beginAnimations:@"animateText" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:1.0f];
[self.lbl setAlpha:0];
[self.lbl setText:@"New Text";
[self.lbl setAlpha:1];
[UIView commitAnimations];

3
これはフェードではありません。これはフェードアウトであり、完全に消えてからフェードインします。これは基本的にスローモーションフリッカーですが、それでもフリッカーです。
SwiftArchitect 2014

18
UILabels lblに名前を付けないでください
rigdonmr 2017年

5

UILabel拡張ソリューション

extension UILabel{

  func animation(typing value:String,duration: Double){
    let characters = value.map { $0 }
    var index = 0
    Timer.scheduledTimer(withTimeInterval: duration, repeats: true, block: { [weak self] timer in
        if index < value.count {
            let char = characters[index]
            self?.text! += "\(char)"
            index += 1
        } else {
            timer.invalidate()
        }
    })
  }


  func textWithAnimation(text:String,duration:CFTimeInterval){
    fadeTransition(duration)
    self.text = text
  }

  //followed from @Chris and @winnie-ru
  func fadeTransition(_ duration:CFTimeInterval) {
    let animation = CATransition()
    animation.timingFunction = CAMediaTimingFunction(name:
        CAMediaTimingFunctionName.easeInEaseOut)
    animation.type = CATransitionType.fade
    animation.duration = duration
    layer.add(animation, forKey: CATransitionType.fade.rawValue)
  }

}

単に呼び出された関数

uiLabel.textWithAnimation(text: "text you want to replace", duration: 0.2)

すべてのヒントの人に感謝します。これが長期的に役立つことを願っています


4

上記のSwiftArchitectのソリューションのSwift 4.2バージョン(素晴らしい作品):

    // Usage: insert view.fadeTransition right before changing content    

extension UIView {

        func fadeTransition(_ duration:CFTimeInterval) {
            let animation = CATransition()
            animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
            animation.type = CATransitionType.fade
            animation.duration = duration
            layer.add(animation, forKey: CATransitionType.fade.rawValue)
        }
    }

呼び出し:

    // This will fade

aLabel.fadeTransition(0.4)
aLabel.text = "text"

3

Swift 2.0:

UIView.transitionWithView(self.view, duration: 1.0, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
    self.sampleLabel.text = "Animation Fade1"
    }, completion: { (finished: Bool) -> () in
        self.sampleLabel.text = "Animation Fade - 34"
})

または

UIView.animateWithDuration(0.2, animations: {
    self.sampleLabel.alpha = 1
}, completion: {
    (value: Bool) in
    self.sampleLabel.alpha = 0.2
})

1
最初のものは機能しますが、2つ目は、経過時間に関係なく、ただちに完了を呼び出します。もう1つの問題は、最初のソリューションでアニメーション化している間はボタンを押すことができないことです。
endavid

アニメーション中に対話を許可するために、オプションを1つ追加しました。[。TransitionCrossDissolve、.AllowUserInteraction]
endavid

self.viewを使用する最初のオプションでは、ビュー全体を変更します。これは、TransitionCrossDissolveのみを使用できることを意味します。代わりに、テキストのみを移行することをお勧めします: "UIView.transitionWithView(self.sampleLabel、duration:1.0 ..."。また、私の場合は "...、completion:nil)"の方がうまくいきました。
Vitalii

3

Swift 5では、次の2つのPlaygroundコードサンプルのいずれかを選択UILabelして、いくつかのクロスディゾルブアニメーションでテキストの変更をアニメーション化できます。


#1。UIViewtransition(with:duration:options:animations:completion:)クラスメソッドの使用

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let label = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = "Car"

        view.backgroundColor = .white
        view.addSubview(label)

        label.translatesAutoresizingMaskIntoConstraints = false
        label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggle(_:)))
        view.addGestureRecognizer(tapGesture)
    }

    @objc func toggle(_ sender: UITapGestureRecognizer) {
        let animation = {
            self.label.text = self.label.text == "Car" ? "Plane" : "Car"
        }
        UIView.transition(with: label, duration: 2, options: .transitionCrossDissolve, animations: animation, completion: nil)
    }

}

let controller = ViewController()
PlaygroundPage.current.liveView = controller

#2。CATransitionおよびCALayeradd(_:forKey:)メソッドを使用する

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let label = UILabel()
    let animation = CATransition()

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = "Car"

        animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
        // animation.type = CATransitionType.fade // default is fade
        animation.duration = 2

        view.backgroundColor = .white
        view.addSubview(label)

        label.translatesAutoresizingMaskIntoConstraints = false
        label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggle(_:)))
        view.addGestureRecognizer(tapGesture)
    }

    @objc func toggle(_ sender: UITapGestureRecognizer) {
        label.layer.add(animation, forKey: nil) // The special key kCATransition is automatically used for transition animations
        label.text = label.text == "Car" ? "Plane" : "Car"
    }

}

let controller = ViewController()
PlaygroundPage.current.liveView = controller

どちらのアニメーションもcrossDissolveと同様に機能します。とにかく、そのような説明的な答えをありがとう。
Yash Bedi

2

Swift 4.2ソリューション(4.0の回答を取り、新しい列挙型をコンパイルして更新する)

extension UIView {
    func fadeTransition(_ duration:CFTimeInterval) {
        let animation = CATransition()
        animation.timingFunction = CAMediaTimingFunction(name:
            CAMediaTimingFunctionName.easeInEaseOut)
        animation.type = CATransitionType.fade
        animation.duration = duration
        layer.add(animation, forKey: CATransitionType.fade.rawValue)
    }
}

func updateLabel() {
myLabel.fadeTransition(0.4)
myLabel.text = "Hello World"
}

2

システムのデフォルト値である0.25 durationと.curveEaseInEaseOutはtimingFunction、アニメーション間の一貫性を保つために望ましい場合が多く、省略できます。

let animation = CATransition()
label.layer.add(animation, forKey: nil)
label.text = "New text"

これはこれを書くのと同じです:

let animation = CATransition()
animation.duration = 0.25
animation.timingFunction = .curveEaseInEaseOut
label.layer.add(animation, forKey: nil)
label.text = "New text"

1

これは、@ SwiftArchitectのコードに基づくC#UIView拡張メソッドです。自動レイアウトが関係し、ラベルのテキストに応じてコントロールを移動する必要がある場合、この呼び出しコードは、ラベル自体ではなく、ラベルのスーパービューを遷移ビューとして使用します。よりカプセル化するために、アクションにラムダ式を追加しました。

public static void FadeTransition( this UIView AView, double ADuration, Action AAction )
{
  CATransition transition = new CATransition();

  transition.Duration = ADuration;
  transition.TimingFunction = CAMediaTimingFunction.FromName( CAMediaTimingFunction.Linear );
  transition.Type = CATransition.TransitionFade;

  AView.Layer.AddAnimation( transition, transition.Type );
  AAction();
}

呼び出しコード:

  labelSuperview.FadeTransition( 0.5d, () =>
  {
    if ( condition )
      label.Text = "Value 1";
    else
      label.Text = "Value 2";
  } );

0

これをSwift遅らせたい場合は、これを試してください:

delay(1.0) {
        UIView.transitionWithView(self.introLabel, duration: 0.25, options: [.TransitionCrossDissolve], animations: {
            self.yourLabel.text = "2"
            }, completion:  { finished in

                self.delay(1.0) {
                    UIView.transitionWithView(self.introLabel, duration: 0.25, options: [.TransitionCrossDissolve], animations: {
                        self.yourLabel.text = "1"
                        }, completion:  { finished in

                    })
                }

        })
    }

@mattによって作成された以下の機能を使用して- https://stackoverflow.com/a/24318861/1982051を

func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

これはSwift 3でこれになります

func delay(_ delay:Double, closure:()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.after(when: when, execute: closure)
}

0

これを達成するためのもう1つの解決策があります。こちらで説明しました。アイデアは、次のように関数をサブクラス化UILabelしてオーバーライドaction(for:forKey:)することです。

class LabelWithAnimatedText: UILabel {
    override var text: String? {
        didSet {
            self.layer.setValue(self.text, forKey: "text")
        }
    }

    override func action(for layer: CALayer, forKey event: String) -> CAAction? {
        if event == "text" {
            if let action = self.action(for: layer, forKey: "backgroundColor") as? CAAnimation {
                let transition = CATransition()
                transition.type = kCATransitionFade

                //CAMediatiming attributes
                transition.beginTime = action.beginTime
                transition.duration = action.duration
                transition.speed = action.speed
                transition.timeOffset = action.timeOffset
                transition.repeatCount = action.repeatCount
                transition.repeatDuration = action.repeatDuration
                transition.autoreverses = action.autoreverses
                transition.fillMode = action.fillMode

                //CAAnimation attributes
                transition.timingFunction = action.timingFunction
                transition.delegate = action.delegate

                return transition
            }
        }
        return super.action(for: layer, forKey: event)
    }
}

使用例:

// do not forget to set the "Custom Class" IB-property to "LabelWithAnimatedText"
// @IBOutlet weak var myLabel: LabelWithAnimatedText!
// ...

UIView.animate(withDuration: 0.5) {
    myLabel.text = "I am animated!"
}
myLabel.text = "I am not animated!"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.