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

Thử cách 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.

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ý khác. API này đóng gói một bộ 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ế hợp lý, khung hiển thị tuỳ chỉnh cũng phải thực hiện những việc 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 phù hợp với bố cục XML của 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 một khung hiển thị đáp ứng tất cả những yêu cầu này. Bài học này sẽ thảo luận cách dùng khung Android để tạo chức năng cốt lõi của lớp thành phần 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 một chế độ xem

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ủa bạn cũng có thể trực tiếp mở rộng 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, tối thiểu bạn phải cung cấp một hàm khởi tạo có đối tượng ContextAttributeSet 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 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 mã đó trong một phần tử XML và kiểm soát giao diện cũng như hành vi của thành phần này 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 các thành phần 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 một 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 sẽ đề 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 của bạn. Thông thường, bạn nên đặt các tài nguyên này vào một 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 hai thuộc tính tuỳ chỉnh là showTextlabelPosition thuộc một thực thể có thể định kiểu tên là PieChart. Theo quy ước, tên của thực thể có thể định kiểu là tên 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 chỉnh sửa mã phổ biến dựa vào quy ước đặt tên này để cung cấp khả năng hoàn thành câu lệnh.

Sau khi định nghĩa các thuộc tính tuỳ chỉnh, bạn có thể sử dụng chúng trong các tệp XML bố cục cũng giống như các thuộc tính tích hợp sẵn. Điểm khác biệt duy nhất nằm ở chỗ 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 về không gian tên http://schemas.android.com/apk/res/android, chúng thuộc http://schemas.android.com/apk/res/[your package name]. Ví dụ: sau đâ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ỳ biệt hiệu 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 khung 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 thành phần 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 lớp ngoài của thành phần hiển thị. Ví dụ: lớp PieChart có một lớp bên trong 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 các thuộc tính tuỳ chỉnh

Khi một thành phần hiển thị được tạo từ 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 truyền vào hàm khởi tạo của thành phần 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 các giá trị thuộc tính không được phân giải.
  • Không áp dụng kiểu.

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

Trình biên dịch tài nguyên Android làm nhiều việc cho bạn để giúp việc gọi obtainStyledAttributes() trở nên 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ã nhận dạng thuộc tính và một tập hợp các hằng số giúp xác định chỉ mục cho từng thuộc tính trong mảng. Bạn sử dụng các hằng số được xác định trước để đọc các thuộc tính từ TypedArray. Dưới đây là cách lớp PieChart đọc các thuộc tính của lớp đó:

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();
   }
}

Xin lưu ý rằng các đố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 thuộc tính chỉ có thể được đọc 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 thuộc tính cho mỗi thuộc tính tuỳ chỉnh. Đoạn mã sau đây cho biết 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(). Các lệnh gọi này rất quan trọng để đảm bảo thành phần hiển thị hoạt động đáng tin cậy. Bạn cần vô hiệu hoá khung hiển thị sau khi có bất kỳ thay đổi nào đối với các thuộc tính mà có thể làm thay đổi giao diện của khung hiển thị đó, để hệ thống biết cần phải 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 có thể ảnh hưởng đến kích thước hoặc hình dạng của thành phần 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.

Khung hiển thị tuỳ chỉnh cũng phải hỗ trợ trình nghe sự kiện để giao tiếp các sự kiện quan trọng. Ví dụ: PieChart sẽ 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 bánh tròn mới.

Bạn rất dễ 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. Dành thời gian để xác định kỹ giao diện của khung hiển thị sẽ giúp giảm chi phí bảo trì trong tương lai. Bạn nên luôn hiển thị mọi thuộc tính ảnh hưởng đến giao diện hoặc hành vi rõ ràng 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 phải hỗ trợ nhiều người dùng. Điều này bao gồm cả người dùng bị khuyết tật khiến họ không nhìn thấy hoặc 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ợ các tay đ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 khung hiển thị dễ tiếp cận, hãy xem nội dung Tăng khả năng hỗ trợ tiếp cận của ứng dụng.