Tạo lớp khung hiển thị

Thử cách sử dụng Compose
Jetpack Compose là bộ công cụ giao diện người dùng được đề xuất cho Android. Tìm hiểu cách sử dụng bố cục trong ứng dụng Compose.

Một khung hiển thị tuỳ chỉnh được thiết kế hợp lý cũng giống như bất kỳ lớp nào được thiết kế hợp lý. Nó đóng gói một tập hợp chức năng cụ thể với một giao diện đơn giản, sử dụng CPU và bộ nhớ một cách hiệu quả, v.v. Ngoài việc là một lớp được thiết kế tốt, khung hiển thị tuỳ chỉnh còn phải có những lợi ích sau:

  • Tuân thủ các tiêu chuẩn của Android.
  • Cung cấp các thuộc tính có thể tạo kiểu tuỳ chỉnh, hoạt động với bố cục XML trên Android.
  • Gửi các sự kiện hỗ trợ tiếp cận.
  • Tương thích với nhiều nền tảng Android.

Khung Android cung cấp một tập hợp các lớp cơ sở và thẻ XML để giúp bạn tạo khung hiển thị đáp ứng tất cả yêu cầu này. Bài học này thảo luận cách sử dụng khung Android để tạo chức năng cốt lõi của lớp khung hiển thị.

Bạn có thể tìm thêm thông tin trong bài viết Thành phần khung hiển thị tuỳ chỉnh.

Lớp con cho khung hiển thị

Tất cả các lớp thành phần hiển thị được xác định trong khung Android đều mở rộng View. Khung hiển thị tuỳ chỉnh cũng có thể mở rộng trực tiếp View hoặc bạn có thể tiết kiệm thời gian bằng cách mở rộng một trong các lớp con của khung hiển thị hiện có, chẳng hạn như Button.

Để cho phép Android Studio tương tác với khung hiển thị của bạn, ở mức tối thiểu, bạn phải cung cấp một hàm khởi tạo lấy Context và đối tượng AttributeSet làm tham số. Hàm khởi tạo này cho phép trình chỉnh sửa bố cục tạo và chỉnh sửa một thực thể của khung hiển thị.

Kotlin

class PieChart(context: Context, attrs: AttributeSet) : View(context, attrs)

Java

class PieChart extends View {
    public PieChart(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
}

Xác định các thuộc tính tuỳ chỉnh

Để thêm một View tích hợp sẵn vào giao diện người dùng, hãy chỉ định thành phần đó trong phần tử XML, đồng thời kiểm soát giao diện và hành vi của phần tử đó bằng các thuộc tính phần tử. Bạn cũng có thể thêm và tạo kiểu cho khung hiển thị tuỳ chỉnh bằng XML. Để bật hành vi này trong khung hiển thị tuỳ chỉnh, hãy làm như sau:

  • Xác định các thuộc tính tuỳ chỉnh cho khung hiển thị của bạn trong phần tử tài nguyên <declare-styleable> .
  • Chỉ định giá trị cho các thuộc tính trong bố cục XML của bạn.
  • Truy xuất giá trị thuộc tính trong thời gian chạy.
  • Áp dụng các giá trị thuộc tính đã truy xuất cho khung hiển thị của bạn.

Phần này thảo luận cách xác định các thuộc tính tuỳ chỉnh và chỉ định giá trị của các thuộc tính đó. Phần tiếp theo đề cập đến việc truy xuất và áp dụng các giá trị trong thời gian chạy.

Để xác định các thuộc tính tuỳ chỉnh, hãy thêm tài nguyên <declare-styleable> vào dự án. Thường thì bạn nên đặt các tài nguyên này vào tệp res/values/attrs.xml. Dưới đây là ví dụ về tệp attrs.xml:

<resources>
   <declare-styleable name="PieChart">
       <attr name="showText" format="boolean" />
       <attr name="labelPosition" format="enum">
           <enum name="left" value="0"/>
           <enum name="right" value="1"/>
       </attr>
   </declare-styleable>
</resources>

Mã này khai báo 2 thuộc tính tuỳ chỉnh là showTextlabelPosition thuộc về một thực thể có thể tạo kiểu có tên là PieChart. Theo quy ước, tên của thực thể có thể định kiểu giống với tên của lớp xác định khung hiển thị tuỳ chỉnh. Mặc dù không nhất thiết phải tuân theo quy ước này, nhưng nhiều trình soạn thảo mã phổ biến phụ thuộc vào quy ước đặt tên này để cung cấp câu lệnh hoàn chỉnh.

Sau khi xác định các thuộc tính tuỳ chỉnh, bạn có thể sử dụng các thuộc tính này trong tệp XML bố cục giống như các thuộc tính tích hợp sẵn. Điểm khác biệt duy nhất là các thuộc tính tuỳ chỉnh của bạn thuộc một không gian tên khác. Thay vì thuộc không gian tên http://schemas.android.com/apk/res/android, chúng thuộc về http://schemas.android.com/apk/res/[your package name]. Ví dụ: dưới đây là cách sử dụng các thuộc tính được xác định cho PieChart:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:custom="http://schemas.android.com/apk/res-auto">
 <com.example.customviews.charting.PieChart
     custom:showText="true"
     custom:labelPosition="left" />
</LinearLayout>

Để tránh phải lặp lại URI không gian tên dài, mẫu sẽ sử dụng lệnh xmlns. Lệnh này chỉ định bí danh custom cho không gian tên http://schemas.android.com/apk/res/com.example.customviews. Bạn có thể chọn bất kỳ bí danh nào bạn muốn cho không gian tên của mình.

Hãy lưu ý tên của thẻ XML sẽ thêm thành phần hiển thị tuỳ chỉnh vào bố cục. Đây là tên đủ điều kiện của lớp khung hiển thị tuỳ chỉnh. Nếu lớp khung hiển thị là một lớp bên trong, hãy đáp ứng điều kiện thêm bằng tên của lớp bên ngoài của khung hiển thị. Ví dụ: lớp PieChart có một lớp bên trong có tên là PieView. Để sử dụng các thuộc tính tuỳ chỉnh của lớp này, bạn cần dùng thẻ com.example.customviews.charting.PieChart$PieView.

Áp dụng thuộc tính tuỳ chỉnh

Khi một khung hiển thị được tạo qua bố cục XML, tất cả thuộc tính trong thẻ XML sẽ được đọc từ gói tài nguyên và được chuyển vào hàm khởi tạo của khung hiển thị dưới dạng AttributeSet. Mặc dù bạn có thể đọc trực tiếp các giá trị từ AttributeSet, nhưng việc này có một số nhược điểm:

  • Các tham chiếu tài nguyên trong giá trị thuộc tính không được phân giải.
  • Kiểu không được áp dụng.

Thay vào đó, hãy truyền AttributeSet cho obtainStyledAttributes(). Phương thức này trả về một mảng TypedArray gồm các giá trị đã bị huỷ tham chiếu và tạo kiểu.

Trình biên dịch tài nguyên Android thực hiện rất nhiều công việc để giúp bạn gọi obtainStyledAttributes() dễ dàng hơn. Đối với mỗi tài nguyên <declare-styleable> trong thư mục res/, R.java được tạo sẽ xác định cả một mảng mã thuộc tính và một tập hợp các hằng số xác định chỉ mục cho mỗi thuộc tính trong mảng đó. Bạn sử dụng các hằng số định sẵn để đọc các thuộc tính qua TypedArray. Dưới đây là cách lớp PieChart đọc các thuộc tính của lớp này:

Kotlin

init {
    context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.PieChart,
            0, 0).apply {

        try {
            mShowText = getBoolean(R.styleable.PieChart_showText, false)
            textPos = getInteger(R.styleable.PieChart_labelPosition, 0)
        } finally {
            recycle()
        }
    }
}

Java

public PieChart(Context context, AttributeSet attrs) {
   super(context, attrs);
   TypedArray a = context.getTheme().obtainStyledAttributes(
        attrs,
        R.styleable.PieChart,
        0, 0);

   try {
       mShowText = a.getBoolean(R.styleable.PieChart_showText, false);
       textPos = a.getInteger(R.styleable.PieChart_labelPosition, 0);
   } finally {
       a.recycle();
   }
}

Lưu ý rằng đối tượng TypedArray là một tài nguyên dùng chung và phải được tái chế sau khi sử dụng.

Thêm thuộc tính và sự kiện

Thuộc tính là một cách hiệu quả để kiểm soát hành vi và giao diện của thành phần hiển thị, nhưng bạn chỉ có thể đọc thuộc tính khi khởi tạo thành phần hiển thị đó. Để cung cấp hành vi động, hãy hiển thị một cặp phương thức getter và setter của thuộc tính cho mỗi thuộc tính tuỳ chỉnh. Đoạn mã sau đây cho thấy cách PieChart hiển thị một thuộc tính có tên là showText:

Kotlin

fun isShowText(): Boolean {
    return mShowText
}

fun setShowText(showText: Boolean) {
    mShowText = showText
    invalidate()
    requestLayout()
}

Java

public boolean isShowText() {
   return mShowText;
}

public void setShowText(boolean showText) {
   mShowText = showText;
   invalidate();
   requestLayout();
}

Xin lưu ý rằng setShowText gọi invalidate()requestLayout(). Những lệnh gọi này rất quan trọng để đảm bảo khung hiển thị hoạt động một cách đáng tin cậy. Bạn cần vô hiệu hoá khung hiển thị sau khi có thay đổi về các thuộc tính có thể làm thay đổi giao diện để hệ thống biết rằng cần vẽ lại. Tương tự, bạn cần yêu cầu một bố cục mới nếu một thuộc tính thay đổi theo cách có thể ảnh hưởng đến kích thước hoặc hình dạng của khung hiển thị. Việc quên các lệnh gọi phương thức này có thể gây ra các lỗi khó tìm.

Chế độ xem tuỳ chỉnh cũng phải hỗ trợ trình nghe sự kiện để thông báo các sự kiện quan trọng. Ví dụ: PieChart hiển thị một sự kiện tuỳ chỉnh có tên là OnCurrentItemChanged để thông báo cho trình nghe rằng người dùng đã xoay biểu đồ hình tròn để tập trung vào một lát hình tròn mới.

Bạn có thể quên hiển thị các thuộc tính và sự kiện, đặc biệt khi bạn là người dùng duy nhất của khung hiển thị tuỳ chỉnh. Việc dành thời gian để xác định cẩn thận giao diện của khung hiển thị sẽ giúp giảm chi phí bảo trì trong tương lai. Quy tắc hay bạn nên tuân thủ là luôn hiển thị mọi thuộc tính ảnh hưởng đến giao diện hoặc hành vi hiển thị của khung hiển thị tuỳ chỉnh.

Thiết kế để hỗ trợ tiếp cận

Khung hiển thị tuỳ chỉnh của bạn phải hỗ trợ nhiều người dùng. Quy định này bao gồm cả những người dùng bị khuyết tật không nhìn thấy hoặc không sử dụng được màn hình cảm ứng. Để hỗ trợ người dùng bị khuyết tật, hãy làm như sau:

  • Gắn nhãn các trường nhập dữ liệu bằng thuộc tính android:contentDescription.
  • Gửi các sự kiện hỗ trợ tiếp cận bằng cách gọi sendAccessibilityEvent() khi thích hợp.
  • Hỗ trợ bộ điều khiển thay thế, chẳng hạn như D-pad hoặc bi xoay.

Để biết thêm thông tin về cách tạo thành phần hiển thị hỗ trợ tiếp cận, hãy xem nội dung Tăng khả năng hỗ trợ tiếp cận cho ứng dụng.