WWDC‑style per‑line text reveal & hide animation for UILabel 🚀
IMG_0675.MP4
- 🔠 Line‑by‑line staggered animation (cascade)
↕️ Opacity 0 → 1 and Y‑offset 8pt → 0- 📐 Scale 0.96 → 1.0 (anchor at bottom)
- 🌫️ Blur 8 → 0 (iOS 17+ GPU via
CIFilter; fallback on iOS 16 toUIVisualEffectView) ▶️ Animate In (animateIn) and ⏹️ Animate Out (animateOut)- 🪄 Triggers only when the label’s superview exists
- ⚡️ Caching of TextKit line layout for performance
- iOS 16.4+
- Swift 5.7+
- UIKit
ℹ️ Important: The original
UILabelbeing animated must have:
lineBreakMode = .byWordWrapping- Initially
isHidden = true
-
Copy
LineByLineTextAnimator.swiftinto your project. -
Ensure you import:
import UIKit import CoreText import CoreImage
// Ensure label.frame is final and label.layoutIfNeeded() has been called
label.isHidden = true // initial state
LineByLineTextAnimator.animateIn(
label: label, // your multiline UILabel
totalDuration: 0.56, // optional, default 0.56s
cascadeFraction: 0.45 // optional, default 0.45
)// Hide immediately and play reverse animation
label.isHidden = true
LineByLineTextAnimator.animateOut(
label: label,
totalDuration: 0.56,
cascadeFraction: 0.45
)In your view controller:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Reveal once
label.isHidden = true
LineByLineTextAnimator.animateIn(label: label)
}
@IBAction func didTapHide(_ sender: UIButton) {
// Hide on demand
label.isHidden = true
LineByLineTextAnimator.animateOut(label: label)
}- Timing: adjust
totalDuration&cascadeFraction. - Spring physics: tweak
UISpringTimingParameters(mass:stiffness:damping:initialVelocity:)in the code. - Blur radius: modify values in the
CIFilteror fallback animation.
- Call
label.layoutIfNeeded()before animation. - Reuse UILabels to benefit from line‑layout caching.
MIT — free to use and modify.