CAAnimation là lớp cơ sở trừu tượng của Core Animation, định nghĩa giao diện chung cho tất cả các loại hoạt ảnh: CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup, CATransition. Bài viết giải thích hệ thống phân cấp lớp, các thuộc tính chính, nhóm hoạt ảnh và các ví dụ thực tế bằng Swift.
Những điểm chính
CAAnimation là một lớp trừu tượng của Core Animation, định nghĩa giao diện chung cho tất cả các hoạt ảnh. Nó triển khai giao thức CAMediaTiming (thời lượng, lặp lại, tự động đảo ngược) và CAMediaTimingFillMode (hành vi trước/sau hoạt ảnh). CAAnimation không thể được khởi tạo trực tiếp — hãy sử dụng một trong các lớp con của nó: CABasicAnimation, CAKeyframeAnimation, CAAnimationGroup, CATransition hoặc CAAnimation (thông qua animationForKeyPath).
Mỗi CAAnimation được thêm vào CALayer thông qua phương thức add(_:forKey:). Tham số forKey là mã định danh duy nhất của hoạt ảnh trên lớp. Một keyPath chỉ có thể có một hoạt ảnh đang hoạt động. Để thay thế hoạt ảnh, hãy sử dụng removeAnimation(forKey:) trước khi thêm hoạt ảnh mới.
Theo Apple, CAAnimation là một thay đổi "tạm thời" của lớp. Sau khi hoạt ảnh hoàn thành, lớp trình bày trở về giá trị của lớp mô hình nếu fillMode và isRemovedOnCompletion không được đặt.
Core Animation cung cấp bốn lớp con chính của CAAnimation, mỗi lớp dành cho một kịch bản hoạt ảnh riêng. Hiểu được hệ thống phân cấp giúp chọn đúng loại cho công việc.
| Lớp | Mục đích | Tính năng chính |
|---|---|---|
| CABasicAnimation | Hoạt ảnh một thuộc tính từ A đến B | fromValue, toValue, byValue, keyPath |
| CAKeyframeAnimation | Hoạt ảnh qua nhiều khung hình chính | values, keyTimes, path, calculationMode |
| CAAnimationGroup | Nhóm nhiều hoạt ảnh | mảng animations, duration đơn nhất |
| CATransition | Chuyển tiếp giữa các trạng thái lớp | type (fade/push/moveIn/reveal), subtype, startProgress |
CABasicAnimation là lớp con đơn giản nhất và phổ biến nhất. CAKeyframeAnimation được sử dụng cho các quỹ đạo phức tạp (ví dụ: chuyển động dọc theo đường cong Bezier). CAAnimationGroup chạy nhiều hoạt ảnh song song. CATransition là chuyển tiếp có sẵn giữa các hình ảnh hoặc trạng thái nội dung.
Giao thức CAMediaTiming là một phần cơ bản của CAAnimation. Nó định nghĩa các thuộc tính thời gian cơ bản: duration, repeatCount, repeatDuration, autoreverses, beginTime (thời gian bắt đầu so với cha), timeOffset (độ lệch trong một chu kỳ), speed (tốc độ phát lại).
Thuộc tính fillMode (CAMediaTimingFillMode) xác định hiển thị lớp trước (backwards) và sau (forwards) hoạt ảnh. Các giá trị: removed (mặc định — trở về lớp mô hình), forwards (giữ nguyên trạng thái cuối), backwards (hiển thị trạng thái ban đầu trước khi bắt đầu), both (kết hợp cả hai hành vi). fillMode chỉ hoạt động khi isRemovedOnCompletion = false.
CAAnimation kế thừa CAMediaTiming và có thể được lồng trong hoạt ảnh cha (CAAnimationGroup). Trong trường hợp này, beginTime được tính so với thời điểm bắt đầu của cha và duration bị giới hạn bởi thời lượng của cha. Speed = 2.0 tăng gấp đôi tốc độ hoạt ảnh.
CAAnimationGroup kết hợp nhiều phiên bản CAAnimation thành một nhóm duy nhất. Tất cả các hoạt ảnh con bắt đầu song song trừ khi beginTime được đặt cho mỗi hoạt ảnh. Nhóm có duration riêng, giới hạn thời lượng tối đa của các hoạt ảnh con. timingFunction của nhóm được sử dụng làm giá trị mặc định nếu hoạt ảnh con không đặt giá trị riêng.
CAKeyframeAnimation tạo hoạt ảnh cho một thuộc tính qua nhiều khung hình chính, được xác định bởi một mảng values. Tham số keyTimes (mảng NSNumber từ 0 đến 1) xác định dấu thời gian cho mỗi khung hình. calculationMode chỉ định phép nội suy: linear, discrete (không nội suy), paced (tốc độ đồng đều), cubic (spline), cubicPaced.
import QuartzCore
// CAAnimationGroup — kết hợp hoạt ảnh
func complexLayerAnimation(_ layer: CALayer) {
let fade = CABasicAnimation(keyPath: "opacity")
fade.fromValue = 1.0
fade.toValue = 0.3
let scale = CABasicAnimation(keyPath: "transform.scale")
scale.fromValue = 1.0
scale.toValue = 1.5
let rotate = CABasicAnimation(keyPath: "transform.rotation.z")
rotate.fromValue = 0
rotate.toValue = Double.pi * 2
let group = CAAnimationGroup()
group.animations = [fade, scale, rotate]
group.duration = 2.0
group.repeatCount = .infinity
group.autoreverses = true
layer.add(group, forKey: "pulse")
}
// CAKeyframeAnimation — chuyển động theo quỹ đạo
func animateAlongPath(_ layer: CALayer) {
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addCurve(
to: CGPoint(x: 200, y: 300),
controlPoint1: CGPoint(x: 100, y: 0),
controlPoint2: CGPoint(x: 100, y: 300)
)
let anim = CAKeyframeAnimation(keyPath: "position")
anim.path = path.cgPath
anim.duration = 1.5
anim.calculationMode = .cubicPaced
anim.rotationMode = .auto
anim.fillMode = .forwards
anim.isRemovedOnCompletion = false
layer.add(anim, forKey: "pathAnim")
layer.position = CGPoint(x: 200, y: 300)
}
// CAKeyframeAnimation với giá trị tùy chỉnh
func bounceAnimation(_ layer: CALayer) {
let bounce = CAKeyframeAnimation(keyPath: "position.y")
bounce.values = [0, -50, 0, -25, 0, -10, 0]
bounce.keyTimes = [0, 0.15, 0.3, 0.45, 0.6, 0.8, 1.0]
bounce.duration = 0.8
bounce.timingFunction = CAMediaTimingFunction(name: .easeOut)
bounce.isAdditive = true // so với vị trí hiện tại
layer.add(bounce, forKey: nil)
}CAAnimationGroup thực thi fade, scale và rotate song song với thời lượng 2.0. CAKeyframeAnimation với path và calculationMode = .cubicPaced cung cấp chuyển động đồng đều dọc theo đường cong Bezier với xoay tự động (rotationMode = .auto). bounceAnimation sử dụng isAdditive cho độ lệch tương đối.
Một ví dụ hoàn chỉnh về CAAnimation cho hoạt ảnh lớp phức tạp sử dụng CATransition để chuyển đổi nội dung và CAAnimationGroup cho hiệu ứng xung.
import UIKit
import QuartzCore
class AnimationDemoView: UIView {
private let demoLayer = CALayer()
private var currentColor: CGColor = UIColor.systemBlue.cgColor
override func layoutSubviews() {
super.layoutSubviews()
demoLayer.frame = CGRect(x: bounds.midX - 40, y: bounds.midY - 40,
width: 80, height: 80)
demoLayer.backgroundColor = currentColor
demoLayer.cornerRadius = 12
layer.addSublayer(demoLayer)
}
func animateTransition() {
// CATransition — chuyển tiếp giữa các trạng thái
let transition = CATransition()
transition.type = .fade
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
demoLayer.add(transition, forKey: nil)
// Thay đổi nội dung qua giao dịch
currentColor = currentColor == UIColor.systemBlue.cgColor
? UIColor.systemRed.cgColor
: UIColor.systemBlue.cgColor
demoLayer.backgroundColor = currentColor
}
func startPulse() {
let scaleUp = CABasicAnimation(keyPath: "transform.scale")
scaleUp.fromValue = 1.0
scaleUp.toValue = 1.3
let fadeOut = CABasicAnimation(keyPath: "opacity")
fadeOut.fromValue = 1.0
fadeOut.toValue = 0.6
let glow = CABasicAnimation(keyPath: "shadowOpacity")
glow.fromValue = 0.0
glow.toValue = 0.8
let group = CAAnimationGroup()
group.animations = [scaleUp, fadeOut, glow]
group.duration = 1.2
group.autoreverses = true
group.repeatCount = .infinity
group.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
demoLayer.add(group, forKey: "pulse")
}
func stopAnimations() {
demoLayer.removeAllAnimations()
demoLayer.transform = CATransform3DIdentity
demoLayer.opacity = 1.0
demoLayer.shadowOpacity = 0.0
}
}CATransition với type: .fade tạo chuyển tiếp mượt mà giữa hai trạng thái backgroundColor. CAAnimationGroup kết hợp scale, opacity và shadowOpacity để tạo hiệu ứng xung. removeAllAnimations() hủy tất cả hoạt ảnh và đưa lớp trở về giá trị lớp mô hình ban đầu.
Các câu hỏi thường gặp
CABasicAnimation tạo hoạt ảnh cho một thuộc tính từ giá trị ban đầu (fromValue) đến giá trị cuối (toValue) với phép nội suy đồng đều. CAKeyframeAnimation cho phép bạn chỉ định một mảng các giá trị trung gian (values) và dấu thời gian (keyTimes) cho hoạt ảnh khung hình chính phi tuyến tính, bao gồm chuyển động dựa trên đường cong thông qua path.
CAAnimationGroup cần thiết khi nhiều hoạt ảnh phải chạy song song với sự đồng bộ được đảm bảo: thời lượng của nhóm giới hạn tất cả các hoạt ảnh con. Sử dụng group cho các hiệu ứng kết hợp: thay đổi tỷ lệ + thay đổi độ mờ + xoay đồng thời.
fillMode xác định hiển thị lớp trước (backwards) và sau (forwards) hoạt ảnh. Giá trị .forwards giữ lớp ở trạng thái cuối sau khi hoạt ảnh hoàn thành (yêu cầu isRemovedOnCompletion = false). .both kết hợp backwards (trạng thái ban đầu trước khi bắt đầu) và forwards.
CAAnimation là một đối tượng hoạt ảnh (chỉ thị) được thêm vào CALayer thông qua layer.add(animation, forKey:). Hoạt ảnh tồn tại như một đối tượng riêng biệt, có thể được tái sử dụng (bằng cách sao chép) và được quản lý thông qua CAMediaTiming. Một lớp có thể có nhiều hoạt ảnh với các khóa khác nhau.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm