CAShapeLayer — khái niệm, thuộc tính và tạo hình

Tác giả: IT Sectr Đã đăng: 2026-06-12 Thời gian đọc: 10 phút

CAShapeLayer là một lớp con của CALayer được thiết kế để kết xuất đường dẫn vector được tăng tốc phần cứng trên GPU. Không giống như CALayer cơ bản, hoạt động với hình ảnh raster thông qua contents, CAShapeLayer kết xuất các hình dạng tùy ý được xác định qua CGPath mà không tạo bộ đệm ngoài màn hình riêng biệt. Theo Apple QuartzCore Documentation, 2025, CAShapeLayer sử dụng tăng tốc phần cứng để làm mịn cạnh và hỗ trợ hoạt ảnh path, strokeStart và strokeEnd. Đây là công cụ tiêu chuẩn để tạo biểu tượng, chỉ báo tiến trình và mặt nạ trong iOS.

Những điểm chính

  • CAShapeLayer — lớp con của CALayer để kết xuất hình vector trên GPU qua CGPath.
  • Việc kết xuất đường dẫn được thực hiện bằng phần cứng mà không tạo bộ đệm raster trung gian — nhanh hơn Core Graphics.
  • Các thuộc tính fillColor, strokeColor, lineWidth, lineCap, lineJoin kiểm soát hình thức của hình dạng.
  • Hoạt ảnh path cho phép biến đổi mượt mà một hình dạng thành hình dạng khác — khả năng chính cho hoạt ảnh UI.
  • strokeStartstrokeEnd được tạo hoạt ảnh để tạo hiệu ứng vẽ đường dẫn — lý tưởng cho chỉ báo tải.

CAShapeLayer là gì?

CAShapeLayer là một lớp chuyên biệt để kết xuất đồ họa vector, được giới thiệu trong iOS 3.0. Không giống như CALayer lưu trữ hình ảnh raster, CAShapeLayer lưu trữ mô tả toán học của một đường dẫn — CGPath — và kết xuất nó trực tiếp trên GPU. Điều này cho phép thu phóng hình dạng mà không mất chất lượng và tạo hoạt ảnh cho các thuộc tính của nó mà không cần vẽ lại nội dung.

Về mặt kiến trúc, CAShapeLayer kế thừa tất cả khả năng của CALayer: bóng, viền, biến đổi, mặt nạ. Nhưng nó thêm các thuộc tính cụ thể để làm việc với đường dẫn: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, miterLimit, strokeStart, strokeEnd và fillRule. Mỗi thuộc tính này có thể được tạo hoạt ảnh qua CABasicAnimation.

Theo Apple Documentation, CAShapeLayer sử dụng tăng tốc phần cứng để kết xuất. Không giống như vẽ qua Core Graphics trong drawRect:, nơi CPU kết xuất đường dẫn vào ngữ cảnh raster, CAShapeLayer gửi lệnh trực tiếp đến GPU qua Metal. Kết quả là hiệu suất cao hơn, đặc biệt trong quá trình hoạt ảnh.

CAShapeLayer đặc biệt hữu ích cho các phần tử giao diện thay đổi hình dạng để phản hồi hành động của người dùng: chỉ báo tiến trình, biểu đồ, biểu tượng thanh tab, mặt nạ cho hoạt ảnh hiển thị nội dung.

Cách CAShapeLayer kết xuất đường dẫn trên GPU

Quy trình kết xuất của CAShapeLayer khác với CALayer cơ bản. Thay vì lưu trữ bộ đệm raster với pixel, CAShapeLayer truyền mô tả đỉnh của đường dẫn đến GPU — một tập hợp các điểm, đường cong Bezier và đoạn thẳng. GPU raster hóa đường dẫn này trong một lần, áp dụng màu tô và màu viền ở giai đoạn shader mảnh.

Cách tiếp cận này mang lại hai lợi thế: thu phóng không mất chất lượng (đồ họa vector vẫn sắc nét ở mọi độ phân giải) và hoạt ảnh hiệu quả — khi đường dẫn thay đổi, GPU chỉ tính toán lại các pixel đã thay đổi, không phải toàn bộ màn hình.

Các thuộc tính chính của CAShapeLayer

path — thuộc tính trung tâm của CAShapeLayer, chấp nhận CGPath. Đường dẫn có thể chứa các đường thẳng, cung, đường cong Bezier và hình chữ nhật. Nó được tạo qua UIBezierPath trong Swift hoặc CGPath trong Core Graphics. Ví dụ: UIBezierPath(roundedRect: rect, cornerRadius: 16).cgPath tạo một hình chữ nhật bo tròn.

  • fillColor — màu tô của đường dẫn đã đóng (CGColor). Nếu nil thì không tô. Hỗ trợ hoạt ảnh.
  • strokeColor — màu viền của đường dẫn. Tạo hoạt ảnh cùng với lineWidth, tạo hiệu ứng vẽ đường dẫn.
  • lineWidth — độ dày của đường viền tính bằng điểm. Mặc định là 1.0. Có thể tạo hoạt ảnh.
  • lineCap — kiểu kết thúc đường: .butt (cắt thẳng), .round (bo tròn), .square (hình chữ nhật có phần nhô ra).
  • lineJoin — kiểu nối đường: .miter (góc nhọn), .round (bo tròn), .bevel (vát).
  • strokeStartstrokeEnd — phần đường dẫn được vẽ từ 0.0 đến 1.0. Tạo hoạt ảnh strokeEnd tạo hiệu ứng hiển thị dần dần.
  • fillRule — quy tắc tô cho các đường dẫn giao nhau: .nonZero (mặc định) hoặc .evenOdd.
  • miterLimit — chiều dài miter tối đa khi lineJoin = .miter. Ngăn các góc dài vô hạn.

Thuộc tính lineDashPattern cho phép tạo các đường gạch ngang. Nó chấp nhận một mảng số: [6, 3] có nghĩa là 6 điểm gạch và 3 điểm khoảng trống. lineDashPhase đặt độ lệch mẫu và có thể được tạo hoạt ảnh để tạo hiệu ứng gạch di chuyển.

CAShapeLayer vs CALayer: khi nào chọn loại nào

Sự lựa chọn giữa CAShapeLayer và CALayer cơ bản phụ thuộc vào loại nội dung. Nếu phần tử là vùng hình chữ nhật có nền, viền và bóng — CALayer là đủ. Nếu phần tử có hình dạng tùy ý, cần hoạt ảnh đường dẫn hoặc thu phóng không mất chất lượng — CAShapeLayer là lựa chọn tốt hơn.

Hiệu suất cũng khác nhau. CALayer với cornerRadius và masksToBounds tạo bộ đệm ngoài màn hình để cắt nội dung, thêm 2–5 ms mỗi khung hình. CAShapeLayer không yêu cầu bộ đệm ngoài màn hình — việc cắt được thực hiện ở cấp độ shader đỉnh. Đối với các phần tử có mặt nạ phức tạp, CAShapeLayer có thể nhanh hơn 2–3 lần.

  • CALayer: phần tử hình chữ nhật, ảnh, video, nội dung có góc bo tròn (cornerRadius), bóng, viền.
  • CAShapeLayer: biểu tượng, biểu đồ, thanh tiến trình, mặt nạ hình dạng tùy ý, đường dẫn hoạt ảnh, hình dạng hoạt ảnh hiển thị.
  • CATextLayer: văn bản cần kết xuất subpixel và lưu đệm glyph.
  • CAGradientLayer: tô màu chuyển sắc — kết hợp với CAShapeLayer qua mask để tạo hình dạng có gradient.

Kết hợp CAShapeLayer với các lớp khác là một mẫu phổ biến. Ví dụ, CAGradientLayer sử dụng CAShapeLayer làm mặt nạ để tạo hình dạng với tô màu chuyển sắc. Cách tiếp cận này cung cấp cả chất lượng vector và tô màu chuyển sắc mà không mất hiệu suất.

Hoạt ảnh CAShapeLayer: path và stroke

Hoạt ảnh path là một trong những tính năng mạnh nhất của CAShapeLayer. Nếu cả hai đường dẫn (ban đầu và cuối cùng) có cùng số điểm điều khiển và đoạn, Core Animation thực hiện nội suy mượt mà giữa chúng. Kết quả là hiệu ứng biến đổi từ hình dạng này sang hình dạng khác.

Điều kiện tương thích đường dẫn: UIBezierPath ban đầu và cuối cùng phải có cấu trúc giống nhau — số lượng lệnh gọi moveTo, addLine, addCurve và addQuadCurve phải khớp nhau. Nếu cấu trúc khác nhau, hoạt ảnh sẽ diễn ra tức thời, không có nội suy.

Theo Apple WWDC 2024, sự kết hợp của strokeStart và strokeEnd là mẫu hoạt ảnh CAShapeLayer được sử dụng phổ biến nhất. Tạo hoạt ảnh strokeEnd từ 0.0 đến 1.0 tạo hiệu ứng vẽ đường dẫn từ đầu đến cuối. Điều này được sử dụng trong chỉ báo tải, hoạt ảnh hiển thị biểu đồ và chuyển tiếp màn hình tùy chỉnh.

Để tạo hiệu ứng nhấp nháy, hãy tạo hoạt ảnh strokeEnd và opacity đồng thời với các hàm thời gian khác nhau. Để tạo hiệu ứng kiến diễu hành, hãy tạo hoạt ảnh lineDashPhase với lineDashPattern cố định. Cả hai kỹ thuật đều được thực hiện qua CABasicAnimation mà không có sự tham gia của CPU.

Hoạt ảnh dưới dạng mặt nạ

CAShapeLayer thường được sử dụng làm mặt nạ cho các lớp khác. Ví dụ, cho hoạt ảnh hiển thị nội dung: ban đầu, mask.path là một hình chữ nhật có kích thước bằng không, và cuối cùng là kích thước đầy đủ. Core Animation nội suy đường dẫn và nội dung hiển thị mượt mà.

Mẫu này được sử dụng trong iOS cho hoạt ảnh mở rộng thẻ, trình bày cửa sổ modal và chuyển tiếp giữa các bộ điều khiển view. Không giống như hoạt ảnh alpha, hoạt ảnh mặt nạ CAShapeLayer cung cấp hiệu ứng hiển thị tự nhiên hơn với các hình dạng tùy ý.

Ví dụ mã với CAShapeLayer trong Swift

Ví dụ đầu tiên — tạo chỉ báo tiến trình hình tròn với hoạt ảnh strokeEnd. Đây là phần tử UI tiêu chuẩn thể hiện các khả năng chính của CAShapeLayer:

swift
func createProgressIndicator(in view: UIView) -> CAShapeLayer {
    let circlePath = UIBezierPath(
        arcCenter: CGPoint(x: 50, y: 50),
        radius: 40,
        startAngle: -.pi / 2,
        endAngle: 3 * .pi / 2,
        clockwise: true
    )

    let trackLayer = CAShapeLayer()
    trackLayer.path = circlePath.cgPath
    trackLayer.strokeColor = UIColor.systemGray5.cgColor
    trackLayer.fillColor = nil
    trackLayer.lineWidth = 8
    view.layer.addSublayer(trackLayer)

    let progressLayer = CAShapeLayer()
    progressLayer.path = circlePath.cgPath
    progressLayer.strokeColor = UIColor.systemBlue.cgColor
    progressLayer.fillColor = nil
    progressLayer.lineWidth = 8
    progressLayer.lineCap = .round
    progressLayer.strokeEnd = 0
    view.layer.addSublayer(progressLayer)

    return progressLayer
}

// Hoạt ảnh đến 75%
progressLayer.animateStrokeEnd(to: 0.75, duration: 1.5)

Ví dụ thứ hai — hoạt ảnh biến đổi giữa hình tròn và hình vuông. Cả hai UIBezierPath đều có cấu trúc tương thích:

swift
let morphLayer = CAShapeLayer()
morphLayer.fillColor = UIColor.systemPurple.cgColor
morphLayer.frame = rect

let circlePath = UIBezierPath(roundedRect: rect, cornerRadius: rect.width / 2)
let squarePath = UIBezierPath(roundedRect: rect, cornerRadius: 0)
morphLayer.path = circlePath.cgPath

let morphAnimation = CABasicAnimation(keyPath: "path")
morphAnimation.toValue = squarePath.cgPath
morphAnimation.duration = 0.6
morphAnimation.autoreverses = true
morphAnimation.repeatCount = .infinity
morphLayer.add(morphAnimation, forKey: "morph")

Ví dụ thứ ba — mặt nạ CAShapeLayer cho hoạt ảnh hiển thị nội dung. Mặt nạ mở rộng từ trung tâm ra các cạnh:

swift
func revealContent(_ view: UIView) {
    let maskLayer = CAShapeLayer()
    let size = view.bounds.size.width * 1.5
    let center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)

    let initialPath = UIBezierPath(arcCenter: center, radius: 0, startAngle: 0, endAngle: .pi * 2, clockwise: true)
    let finalPath = UIBezierPath(arcCenter: center, radius: size, startAngle: 0, endAngle: .pi * 2, clockwise: true)

    maskLayer.path = initialPath.cgPath
    view.layer.mask = maskLayer

    let animation = CABasicAnimation(keyPath: "path")
    animation.toValue = finalPath.cgPath
    animation.duration = 0.4
    animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
    maskLayer.add(animation, forKey: "reveal")
    maskLayer.path = finalPath.cgPath
}

Các câu hỏi thường gặp

CAShapeLayer khác với vẽ trong drawRect như thế nào?

drawRect sử dụng CPU để kết xuất vào ngữ cảnh raster — điều này chậm cho hoạt ảnh. CAShapeLayer kết xuất đường dẫn trên GPU, cung cấp 60 FPS trong quá trình hoạt ảnh path, strokeEnd và biến đổi. Ngoài ra, CAShapeLayer không yêu cầu vẽ lại khi thay đổi kích thước — hình dạng được thu phóng vector.

Tại sao hoạt ảnh path không hoạt động mượt mà?

Hoạt ảnh đường dẫn mượt mà yêu cầu cấu trúc giống hệt nhau của UIBezierPath ban đầu và cuối cùng. Số lượng lệnh gọi moveTo, addLine, addCurve phải khớp nhau. Sử dụng UIBezierPath với cùng số lượng đoạn cho hình dạng ban đầu và cuối cùng.

Làm cách nào để tạo đường gạch ngang trong CAShapeLayer?

Đặt lineDashPattern — một mảng số xen kẽ độ dài gạch và khoảng trống. Ví dụ, [8, 4] tạo gạch 8pt với khoảng trống 4pt. Để tạo hiệu ứng kiến diễu hành, hãy tạo hoạt ảnh lineDashPhase qua CABasicAnimation với hàm thời gian tuyến tính.

Có thể sử dụng CAShapeLayer làm mặt nạ không?

Có, đây là một trong những trường hợp sử dụng chính. Gán CAShapeLayer cho thuộc tính mask của bất kỳ CALayer nào, bao gồm CAGradientLayer và các lớp con khác. Tạo hoạt ảnh cho đường dẫn mặt nạ tạo hiệu ứng hiển thị nội dung mượt mà qua hình dạng tùy ý.

Làm cách nào để tô màu chuyển sắc cho hình dạng qua CAShapeLayer?

Tạo CAGradientLayer và đặt mask = CAShapeLayer với đường dẫn mong muốn. Màu chuyển sắc sẽ chỉ hiển thị bên trong đường dẫn mặt nạ. Mẫu này kết hợp lợi thế hình dạng vector của CAShapeLayer và tô màu chuyển sắc của CAGradientLayer.

Tổng kết

  • CAShapeLayer — lớp con của CALayer để kết xuất đường dẫn vector được tăng tốc phần cứng trên GPU qua CGPath.
  • Các thuộc tính chính: path, fillColor, strokeColor, lineWidth, lineCap, lineJoin, strokeStart, strokeEnd.
  • Hoạt ảnh path tạo biến đổi hình dạng — yêu cầu cấu trúc giống hệt nhau của đường dẫn ban đầu và cuối cùng.
  • Hoạt ảnh strokeEnd — mẫu tiêu chuẩn cho chỉ báo tiến trình và vẽ đường dẫn.
  • CAShapeLayer không yêu cầu bộ đệm ngoài màn hình để tạo mặt nạ, không giống như CALayer với masksToBounds.
  • Được sử dụng làm mặt nạ cho CAGradientLayer, tạo hình dạng với tô màu chuyển sắc.
  • Đối với đường gạch ngang, sử dụng lineDashPattern với hoạt ảnh lineDashPhase để tạo hiệu ứng chuyển động.

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.

Thảo luận dự án

Đọc thêm