Layer là một sự trừu tượng của nội dung đồ họa quản lý trình bày trực quan của các phần tử giao diện trong ứng dụng di động. Không giống như UIView, layer không xử lý sự kiện chạm và không tham gia vào Auto Layout — nhiệm vụ duy nhất của nó là render, hoạt ảnh và tổng hợp pixel. Theo Apple QuartzCore Documentation, 2025, mỗi UIView trong iOS đều có một CALayer liên kết thực sự quản lý việc vẽ và hoạt ảnh. Hiểu cấu trúc của các layer cho phép nhà phát triển kiểm soát hiệu suất render ở cấp độ từng pixel riêng lẻ.
Những điểm chính
Layer là một đối tượng hệ thống đồ họa cấp thấp lưu trữ hình ảnh bitmap của một phần màn hình và quản lý các thuộc tính trực quan của nó: vị trí, kích thước, xoay, độ mờ, bóng và màu sắc. Trong iOS, mỗi UIView đều có một CALayer tích hợp sẵn có thể truy cập qua thuộc tính layer. Nhà phát triển có thể làm việc trực tiếp với layer, bỏ qua UIView, để kiểm soát render chi tiết.
Kiến trúc layer tuân theo mẫu Model-View-Controller, nơi CALayer đóng vai trò là Model — nó lưu trữ trạng thái của các thuộc tính trực quan. Core Animation là Controller quản lý các chuyển đổi hoạt ảnh giữa các trạng thái. View (UIView) là một lớp bọc tùy chọn thêm xử lý chạm và tham gia Auto Layout.
Theo Apple WWDC 2024, pipeline render hiện đại của iOS sử dụng Metal để tổng hợp layer. Mỗi CALayer được render vào một bộ đệm riêng biệt, sau đó Core Animation tổng hợp tất cả bộ đệm thành hình ảnh cuối cùng, có tính đến độ mờ và chế độ hòa trộn.
Trong Android, tương tự của layer là View và Drawable nền, nhưng làm việc trực tiếp với layer đồ họa có sẵn qua Canvas và RenderNode trong Android 10+. Hiểu khái niệm layer rất quan trọng để tối ưu hóa render trên cả hai nền tảng.
Sự khác biệt chính nằm ở lĩnh vực trách nhiệm. View xử lý đầu vào người dùng (chạm, cử chỉ), định vị (Auto Layout, frame) và vòng đời. Layer chỉ chịu trách nhiệm trình bày trực quan: render nội dung, hoạt ảnh thuộc tính và tổng hợp với các layer khác.
Sự tách biệt này cho phép lưu cache biểu diễn bitmap của layer độc lập với View. Nếu layer không thay đổi, Core Animation sử dụng khung hình đã lưu cache mà không gọi drawRect. Đối với các phần tử tĩnh, điều này mang lại tăng hiệu suất đáng kể mà không cần thay đổi mã.
iOS cung cấp một hệ thống phân cấp phong phú các lớp kế thừa từ CALayer. Mỗi lớp con được tối ưu hóa cho một kịch bản cụ thể: hiển thị văn bản, đồ họa vector, chuyển màu hoặc biến đổi 3D. Chọn đúng loại layer ảnh hưởng trực tiếp đến hiệu suất render.
Trong Android, khái niệm layer được triển khai qua RenderNode, ViewLayer và HardwareRenderer. Bắt đầu từ Android 5.0 (API 21), mỗi View được render vào layer tăng tốc phần cứng riêng, cho phép hoạt ảnh mà không cần gọi onDraw.
Tính linh hoạt bổ sung trong iOS được cung cấp bởi CAReplicatorLayer và CAEmitterLayer. Cái đầu tiên được sử dụng để tạo các mẫu lặp lại, cái thứ hai cho hệ thống hạt. Cả hai đều chạy độc quyền trên GPU, cho phép tạo hiệu ứng trực quan phức tạp mà không mất hiệu suất.
Hệ thống phân cấp layer trong iOS tuân theo cấu trúc cây: mỗi CALayer có thể chứa nhiều sublayer con. Tất cả các biến đổi áp dụng cho layer cha — tỷ lệ, xoay, dịch chuyển — tự động áp dụng cho các phần tử con. Điều này đảm bảo tính nhất quán trực quan trong quá trình hoạt ảnh.
Tổng hợp cảnh được thực hiện bởi Core Animation theo thứ tự sau: đầu tiên nền được render, sau đó mỗi layer con theo thứ tự từ dưới lên trên. Đối với mỗi layer, Core Animation kiểm tra các thuộc tính độ mờ, mặt nạ và chế độ hòa trộn, sau đó tổng hợp chúng thành khung hình cuối cùng.
Theo Apple Documentation, tổng hợp layer với opaque = true và không có kênh alpha được thực hiện mà không cần thêm bước — GPU chỉ đơn giản sao chép pixel lên layer trước đó. Nếu layer có độ trong suốt, GPU thực hiện hòa trộn alpha, yêu cầu thêm tài nguyên tính toán.
Trong Android, tổng hợp layer được thực hiện qua SurfaceFlinger — một dịch vụ hệ thống nhận bộ đệm từ mỗi ứng dụng và tổng hợp chúng theo thứ tự z. Mỗi Window trong Android là một Surface riêng biệt có thể chứa nhiều layer đồ họa.
CALayer.mask — một thuộc tính cho phép áp dụng mặt nạ có hình dạng tùy ý lên layer. Mặt nạ có thể là bất kỳ CALayer nào khác — ví dụ: CAShapeLayer với đường tròn hoặc CAGradientLayer để tạo chuyển đổi độ mờ mượt mà. Sử dụng mặt nạ làm tăng tải GPU vì yêu cầu thêm bước render để tính giá trị alpha cho mỗi pixel.
Để cắt hình chữ nhật đơn giản, nên sử dụng cornerRadius và masksToBounds. Không giống như mặt nạ qua thuộc tính mask, cornerRadius được xử lý bằng phần cứng ở giai đoạn rasterization và không yêu cầu bước bổ sung.
shouldRasterize là thuộc tính CALayer quan trọng để tối ưu hóa hiệu suất. Khi shouldRasterize được đặt thành true, Core Animation render layer và tất cả sublayer của nó vào một bộ đệm offscreen riêng biệt. Trong các khung hình tiếp theo, hình ảnh bitmap đã lưu cache được sử dụng thay vì render lại.
Lưu cache hiệu quả cho các layer tĩnh hoặc hiếm khi thay đổi: bóng, chuyển màu, văn bản với góc bo tròn. Tuy nhiên, đối với các layer thường xuyên cập nhật (hoạt ảnh, video, cuộn), rasterization có thể làm giảm hiệu suất vì mỗi khung hình yêu cầu tái tạo cache.
Theo nghiên cứu của Objc.io, sử dụng shouldRasterize đúng cách trên iPad Pro giảm thời gian render một màn hình phức tạp từ 25 ms xuống 8 ms — hơn ba lần. Điều kiện chính là layer không nên thay đổi nhiều hơn một lần mỗi 3–5 khung hình.
Ví dụ đầu tiên minh họa thiết lập các thuộc tính trực quan cơ bản của CALayer trong Swift — bo góc, bóng và viền:
import UIKit
class StyledView: UIView {
override func awakeFromNib() {
super.awakeFromNib()
layer.cornerRadius = 12
layer.masksToBounds = false
layer.shadowColor = UIColor.darkGray.cgColor
layer.shadowOpacity = 0.3
layer.shadowOffset = CGSize(width: 0, height: 4)
layer.shadowRadius = 8
}
}
Ví dụ thứ hai — tạo hoạt ảnh layer trong Swift sử dụng CABasicAnimation. Thuộc tính position được tạo hoạt ảnh mà không có sự tham gia của UIView:
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = NSValue(cgPoint: CGPoint(x: 0, y: 0))
animation.toValue = NSValue(cgPoint: CGPoint(x: 150, y: 300))
animation.duration = 1.0
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
targetLayer.add(animation, forKey: "moveAnimation")
Ví dụ thứ ba — làm việc với RenderNode trong Kotlin trên Android. RenderNode là tương tự trực tiếp của CALayer, cho phép thao tác với layer đồ họa ở cấp độ Canvas:
import android.graphics.renderer.RenderNode
fun createLayer(): RenderNode {
val node = RenderNode("customLayer")
node.setPosition(0, 0, 300, 200)
node.setScaleX(1.5f)
node.setScaleY(1.5f)
val canvas = node.beginRecording()
canvas.drawColor(android.graphics.Color.BLUE)
node.endRecording()
return node
}
Câu hỏi thường gặp
UIView là một lớp bọc quanh CALayer thêm xử lý chạm và tham gia Auto Layout. Layer chỉ xử lý render và hoạt ảnh. Bạn có thể làm việc trực tiếp với CALayer, nhưng UIView là cần thiết để xử lý sự kiện đầu vào.
shouldRasterize bật lưu cache layer vào bộ đệm offscreen riêng biệt. Sử dụng cho các phần tử tĩnh hoặc hiếm khi thay đổi có bóng hoặc tổng hợp phức tạp. Không sử dụng cho các layer thường xuyên tạo hoạt ảnh — tái tạo cache sẽ đắt hơn render trực tiếp.
Đặt thuộc tính cornerRadius để bo góc và masksToBounds = true để cắt nội dung theo ranh giới layer. Đối với bóng, masksToBounds phải là false, nếu không bóng sẽ bị cắt — trong trường hợp này, hãy sử dụng một layer riêng cho bóng.
Có, RenderNode trong Android 10+ cung cấp chức năng tương tự: quản lý vị trí, tỷ lệ, xoay và độ mờ ở cấp độ layer đồ họa. Canvas và HardwareRenderer cung cấp render dựa trên GPU. Tuy nhiên, về mặt kiến trúc, Android không tách biệt View và layer một cách chặt chẽ như iOS.
Bóng trong CALayer được tính qua shadowPath hoặc tự động dựa trên kênh alpha. Tính toán tự động yêu cầu duyệt qua tất cả pixel của layer, rất tốn kém. Chỉ định một shadowPath rõ ràng — một hình chữ nhật hoặc UIBezierPath — điều này cho phép GPU tính bóng mà không cần duyệt nội dung.
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