Chế độ xem tùy chỉnh và vẽ trong phát triển di động: bản chất, API nào và cách hoạt động

Tác giả: IT Sectr Đã đăng: 2026-08-01 Thời gian đọc: 11 phút

Chế độ xem tùy chỉnh là nền tảng của giao diện độc đáo cho bất kỳ ứng dụng di động nào. Chế độ xem tùy chỉnh trong ứng dụng di động cho phép bạn tạo đồ họa, hoạt ảnh và các yếu tố riêng không có trong các thành phần tiêu chuẩn. Theo Apple Developer, 2025, drawRect vẫn là phương thức vẽ tùy chỉnh chính trong phát triển di động iOS. Trên Android, onDraw với Canvas đóng vai trò tương tự, còn trong Flutter — CustomPainter.

Những điểm chính

  • Chế độ xem tùy chỉnh — các thành phần do người dùng định nghĩa với logic vẽ, kích thước và hành vi riêng trong ứng dụng di động.
  • drawRect — phương thức UIView trên iOS để vẽ tùy chỉnh qua Core Graphics và CGContext.
  • onDraw — phương thức View trên Android để vẽ qua Canvas và Paint với hệ thống đo lường onMeasure.
  • CustomPainter — lớp Flutter để vẽ trên Canvas với các phương thức paint và shouldRepaint.
  • Đo lường — quá trình xác định kích thước của Chế độ xem qua sizeThatFits trên iOS, onMeasure trên Android và computeDryLayout trong Flutter.

Chế độ xem tùy chỉnh là gì và tại sao cần chúng trong ứng dụng di động

Chế độ xem tùy chỉnh là các thành phần giao diện do người dùng định nghĩa ghi đè các phương thức vẽ và đo lường tiêu chuẩn để tạo đồ họa độc đáo. Biểu đồ, hoạt ảnh, sơ đồ, yếu tố trò chuyện tùy chỉnh và mặt nạ AR — đây là những trường hợp sử dụng điển hình của chế độ xem tùy chỉnh trong ứng dụng di động. Các thành phần UI tiêu chuẩn (Button, TextView, Label) bao phủ 80% nhiệm vụ, nhưng 20% còn lại yêu cầu kiểm soát hoàn toàn việc vẽ trong phát triển di động. Vẽ trong phát triển di động là kỹ năng phân biệt nhà phát triển junior với senior.

Khi nào chế độ xem tùy chỉnh là hợp lý

Chế độ xem tùy chỉnh trong ứng dụng di động cần thiết cho đồ họa 2D độc đáo, hoạt ảnh phức tạp, biểu đồ và trực quan hóa dữ liệu. Nếu UIKit tiêu chuẩn không cung cấp yếu tố cần thiết — một chế độ xem tùy chỉnh được tạo ra. Trong ứng dụng di động, chế độ xem tùy chỉnh được sử dụng cho thanh tiến trình, nút tùy chỉnh, tô màu chuyển sắc, biểu tượng hoạt ảnh và canvas vẽ bằng ngón tay. Quan trọng là không lạm dụng — đối với kiểu dáng đơn giản, chỉ cần cấu hình các thành phần tiêu chuẩn qua API Giao diện.

Chế độ xem tùy chỉnh trên iOS: drawRect và Core Graphics

Trên iOS, chế độ xem tùy chỉnh được tạo bằng cách kế thừa UIView và ghi đè phương thức drawRect. drawRect được gọi ở lần hiển thị đầu tiên và sau mỗi lần gọi setNeedsDisplay(). Bên trong drawRect, nhà phát triển nhận được CGContext qua UIGraphicsGetCurrentContext() — một canvas cho đường thẳng, hình dạng, gradient và văn bản. Core Graphics (Quartz 2D) là công cụ kết xuất cấp thấp dựa trên CPU cho phép kiểm soát hoàn toàn từng pixel. UIBezierPath là một trình bao bọc tiện lợi để tạo đường dẫn với cú pháp ngắn gọn.

swift
class CircleView: UIView {
    private var fillColor: UIColor = .systemBlue

    override func drawRect(_ rect: CGRect) {
        guard let ctx = UIGraphicsGetCurrentContext() else { return }
        ctx.setFillColor(fillColor.cgColor)
        ctx.addEllipse(in: bounds.insetBy(dx: 4, dy: 4))
        ctx.drawPath(using: .fill)
    }

    func updateColor(_ newColor: UIColor) {
        fillColor = newColor
        setNeedsDisplay()
    }
}

Core Graphics: CGContext, CGGradient và các phép biến đổi

Core Graphics cung cấp CGContext — một canvas cho tất cả các thao tác vẽ. CGGradient tạo gradient tuyến tính và xuyên tâm với hỗ trợ CGColorSpace (sRGB, Display P3). Các phép biến đổi được thực hiện qua CGAffineTransform — ma trận 3x3 cho xoay, co giãn và dịch chuyển. CGContextTranslateCTM, CGContextRotateCTM và CGContextScaleCTM sửa đổi hệ tọa độ. Core Graphics chạy trên CPU, vì vậy đồ họa phức tạp có thể làm quá tải bộ xử lý — hãy sử dụng Metal để tăng tốc GPU.

UIBezierPath để tạo hình dạng

UIBezierPath là một trình bao bọc hướng đối tượng trên CGPath. Phương thức addArc(withCenter:radius:startAngle:endAngle:clockwise:) tạo cung và hình tròn, addCurve tạo đường cong Bézier. Các đường dẫn hỗ trợ các thao tác hợp nhất, giao nhau và trừ qua addClip. UIBezierPath tiện lợi cho mặt nạ tùy chỉnh (maskView), đường cắt và hình dạng phức tạp — ngôi sao, trái tim, biểu tượng tùy chỉnh.

Chế độ xem tùy chỉnh trên Android: onDraw và Canvas

Trên Android, chế độ xem tùy chỉnh mở rộng View với onDraw(Canvas) được ghi đè. Canvas chứa tất cả các phương thức vẽ trong phát triển di động: drawCircle, drawRect, drawLine, drawText, drawBitmap, drawPath và drawRoundRect. Paint cấu hình các tham số — màu sắc, độ dày đường, kiểu (FILL, STROKE, FILL_AND_STROKE), khử răng cưa (isAntiAlias) và kích thước văn bản. onDraw được gọi mỗi lần invalidate() và không được chứa các thao tác nặng — tất cả tính toán đều được lưu vào bộ nhớ đệm.

kotlin
class CustomCircleView(context: Context, attrs: AttributeSet?)
    : View(context, attrs) {

    private val paint = Paint().apply {
        style = Paint.Style.FILL
        color = Color.BLUE
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val cx = width / 2f
        val cy = height / 2f
        val radius = minOf(cx, cy) - 4f
        canvas.drawCircle(cx, cy, radius, paint)
    }
}

Path và hoạt ảnh trên Android

Path trên Android tương đương với UIBezierPath: addCircle, addRect, addOval, lineTo, cubicTo và quadTo. PathMeasure tính toán độ dài đường dẫn và tọa độ tại bất kỳ điểm nào — hữu ích để tạo hoạt ảnh cho chuyển động của đối tượng dọc theo đường dẫn. Đối với hoạt ảnh, sử dụng ValueAnimator với invalidate() trong callback. Trình hoạt ảnh có thể thay đổi màu sắc, bán kính, vị trí — bất kỳ thuộc tính nào ảnh hưởng đến việc vẽ. Chế độ xem tùy chỉnh trên Android cũng hỗ trợ StateListDrawable và animated-vector cho hoạt ảnh qua XML.

Shader và gradient trong Canvas

Gradient trên Android được đặt qua Shader — LinearGradient, RadialGradient và SweepGradient. Shader được gán cho Paint qua paint.setShader(shader). LinearGradient tạo gradient tuyến tính giữa hai điểm với các vị trí màu tùy chọn. RadialGradient — xuyên tâm từ trung tâm ra các cạnh. SweepGradient — hình nón quanh một điểm trung tâm. Shader.TileMode (CLAMP, REPEAT, MIRROR) xác định hành vi bên ngoài ranh giới khu vực.

CustomPainter trong Flutter: vẽ trên Canvas

Flutter sử dụng CustomPainter — một lớp với các phương thức paint(Canvas canvas, Size size) và shouldRepaint. Canvas trong Flutter cung cấp các phương thức tương tự như trong Android: drawCircle, drawRect, drawLine, drawPath, drawParagraph và drawImage. Paint trong Flutter cấu hình màu sắc, độ dày, kiểu và khử răng cưa. Flutter không sử dụng drawRect hay onDraw — tất cả việc vẽ đều thông qua CustomPainter, được nhúng trong widget CustomPaint.

dart
class CirclePainter extends CustomPainter {
  final Color color;

  CirclePainter({required this.color});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    final radius = size.shortestSide / 2 - 4;
    canvas.drawCircle(size.center(Offset.zero), radius, paint);
  }

  @override
  bool shouldRepaint(CirclePainter oldDelegate) =>
    oldDelegate.color != color;
}

shouldRepaint và RepaintBoundary

shouldRepaint xác định liệu CustomPainter có cần vẽ lại hay không. Chỉ trả về true khi dữ liệu ảnh hưởng đến kết xuất thay đổi — màu sắc, kích thước, dữ liệu biểu đồ. RepaintBoundary cách ly việc vẽ lại vào một lớp riêng biệt — sử dụng cho các widget hiếm khi thay đổi. Flutter không có setNeedsDisplay hay invalidate — việc vẽ lại được kích hoạt qua setState hoặc ValueNotifier với lắng nghe thay đổi.

Gradient và các phép biến đổi trong Flutter

Flutter hỗ trợ LinearGradient, RadialGradient và SweepGradient — các loại tương tự như trong Android. Gradient tạo Shader cho Paint qua createShader(Rect bounds). Các phép biến đổi được thực hiện qua canvas.rotate, canvas.scale, canvas.translate và canvas.skew. Flutter sử dụng ma trận biến đổi 4x4 (Matrix4) cho widget Transform. Hoạt ảnh vẽ trong Flutter được thực hiện với AnimationController kết hợp với setState để vẽ lại CustomPainter.

Đo lường chế độ xem tùy chỉnh: các phương thức sizeThatFits, onMeasure và computeDryLayout

Đo lường chính xác chế độ xem tùy chỉnh là nền tảng của hành vi giao diện có thể dự đoán. Trên iOS, kích thước của Chế độ xem được xác định qua sizeThatFits và intrinsicContentSize. sizeThatFits trả về kích thước tối ưu cho các ràng buộc nhất định. intrinsicContentSize — kích thước tự nhiên của nội dung mà không có ràng buộc bên ngoài. Trên Android, đo lường được thực hiện trong onMeasure với các tham số MeasureSpec (UNSPECIFIED, EXACTLY, AT_MOST). Trong Flutter, kích thước được truyền cho paint(Canvas, Size) và có thể được tính qua computeDryLayout hoặc LayoutBuilder.

sizeThatFits và intrinsicContentSize trên iOS

intrinsicContentSize trả về CGSize — kích thước tự nhiên của Chế độ xem dựa trên nội dung của nó. setContentHuggingPriority và setContentCompressionResistancePriority kiểm soát hành vi trong khi kéo giãn và nén. sizeThatFits được hệ thống gọi để tính toán kích thước trong Auto Layout. Đối với chế độ xem tùy chỉnh, hãy ghi đè intrinsicContentSize nếu thành phần của bạn có kích thước tự nhiên — ví dụ, một hình tròn luôn phải là 100x100.

onMeasure và MeasureSpec trên Android

onMeasure chấp nhận widthMeasureSpec và heightMeasureSpec. MeasureSpec chứa chế độ và kích thước: UNSPECIFIED (không ràng buộc, Chế độ xem tự chọn kích thước), EXACTLY (kích thước chính xác từ cha), AT_MOST (kích thước tối đa). setMeasuredDimension(width, height) lưu kết quả đo lường. Khi dữ liệu thay đổi, hãy gọi requestLayout() để đo lại. ViewGroup lồng nhau yêu cầu ghi đè onLayout để sắp xếp các phần tử con.

Nền tảngPhương thức đo lườngGọi khi thay đổiTrả về
iOSsizeThatFits / intrinsicContentSizesetNeedsLayout / invalidateIntrinsicContentSizeCGSize
AndroidonMeasure / setMeasuredDimensionrequestLayout / invalidatevoid (lưu kích thước)
FluttercomputeDryLayoutsetState / LayoutBuilderSize

computeDryLayout trong Flutter

computeDryLayout là phương thức RenderObject để tính toán kích thước mà không cần chu kỳ bố cục đầy đủ. LayoutBuilder.getSize — một giải pháp thay thế để lấy không gian có sẵn trong phương thức build. Trong Flutter, kích thước canvas được truyền cho paint dưới dạng Size và không yêu cầu đo lường riêng — CustomPainter vẽ trong các ranh giới được truyền. Tuy nhiên, đối với RenderObject tùy chỉnh, bạn cần ghi đè performLayout và computeDryLayout.

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

drawRect trên iOS là gì và khi nào nó được gọi?

drawRect là phương thức UIView để vẽ tùy chỉnh qua Core Graphics. Nó được gọi ở lần hiển thị đầu tiên của Chế độ xem và sau mỗi lần gọi setNeedsDisplay(). Sử dụng CGContext trong drawRect cho đường thẳng, hình dạng và văn bản.

Làm thế nào để vẽ trên Android bằng Canvas?

Tạo một lớp mở rộng View, ghi đè onDraw(Canvas canvas) và sử dụng Canvas API: drawCircle, drawRect, drawPath. Paint cấu hình màu sắc, độ dày và kiểu. Để cập nhật, hãy gọi invalidate().

CustomPainter trong Flutter là gì?

CustomPainter là một lớp Flutter để vẽ tùy chỉnh trên Canvas. Triển khai các phương thức paint(Canvas, Size) và shouldRepaint. Nó được đặt qua widget CustomPaint. Flutter không có drawRect — tất cả việc vẽ đều thông qua CustomPainter.

Làm thế nào để đo kích thước của chế độ xem tùy chỉnh?

Trên iOS sử dụng sizeThatFits và intrinsicContentSize. Trên Android — onMeasure với MeasureSpec. Trong Flutter, kích thước được truyền cho paint(Canvas, Size) hoặc tính qua computeDryLayout. Mỗi nền tảng sử dụng phương thức đo lường riêng của mình.

Khi nào nên sử dụng chế độ xem tùy chỉnh thay vì các thành phần tiêu chuẩn?

Chế độ xem tùy chỉnh cần thiết cho đồ họa độc đáo, hoạt ảnh, biểu đồ và các yếu tố không thể triển khai bằng UIKit hoặc View tiêu chuẩn. Đối với kiểu dáng đơn giản, chỉ cần cấu hình các thành phần tiêu chuẩn — đừng làm phức tạp kiến trúc một cách không cần thiết.

Tóm tắt

  • Chế độ xem tùy chỉnh — nền tảng của giao diện độc đáo cho biểu đồ, hoạt ảnh và các yếu tố không tiêu chuẩn trong ứng dụng di động.
  • drawRect — phương thức iOS để vẽ qua Core Graphics với CGContext và UIBezierPath.
  • onDraw — phương thức Android để vẽ qua Canvas và Paint với hỗ trợ Path và Shader.
  • CustomPainter — lớp Flutter để vẽ trên Canvas với shouldRepaint và RepaintBoundary.
  • Đo lường — xác thực kích thước qua sizeThatFits (iOS), onMeasure (Android) và computeDryLayout (Flutter).
  • Vẽ trong phát triển di động tuân theo một mô hình thống nhất trên tất cả các nền tảng: lấy ngữ cảnh, cấu hình kiểu và vẽ các nguyên thủy.
  • Lưu vào bộ nhớ đệm các đối tượng vẽ (Paint, Path) — không tạo chúng bên trong drawRect, onDraw hoặc paint để có hiệu suất ổn định.

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