Cung cấp chế độ xem thẻ

Tạo dựng ứng dụng hiệu quả hơn với Compose
Tạo giao diện người dùng đẹp mắt mà không cần nhiều mã nguồn bằng Jetpack Compose cho hệ điều hành Android TV.

Trong bài học trước, bạn đã tạo một trình duyệt danh mục, được triển khai trong mảnh duyệt qua, cho thấy danh sách các mục nội dung nghe nhìn. Trong bài học này, bạn sẽ tạo khung hiển thị thẻ cho các mục nội dung đa phương tiện rồi trình bày các mục đó trong mảnh duyệt qua.

Lớp BaseCardView và các lớp con cho thấy siêu dữ liệu liên kết với một mục nội dung đa phương tiện. Lớp ImageCardView dùng trong bài học này sẽ hiển thị một hình ảnh cho nội dung cùng với tiêu đề của mục nội dung đa phương tiện.

Ngoài ra, hãy xem cách triển khai mẫu trong ứng dụng mẫu Leanback.

Chế độ xem thẻ ứng dụng

Hình 1. Chế độ xem thẻ hình ảnh ứng dụng mẫu Leanback khi được chọn.

Tạo người trình bày thẻ

Presenter tạo khung hiển thị và liên kết các đối tượng với các đối tượng đó theo yêu cầu. Trong mảnh duyệt qua nơi ứng dụng của bạn hiển thị nội dung cho người dùng, bạn sẽ tạo một Presenter cho thẻ nội dung và truyền nó đến bộ chuyển đổi để thêm nội dung vào màn hình. Trong mã sau, CardPresenter được tạo trong lệnh gọi lại onLoadFinished() của LoaderManager:

Kotlin

override fun onLoadFinished(loader: Loader<HashMap<String, List<Movie>>>, data: HashMap<String, List<Movie>>) {
    rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
    val cardPresenter = CardPresenter()

    var i = 0L

    data.entries.forEach { entry ->
        val listRowAdapter = ArrayObjectAdapter(cardPresenter).apply {
            entry.value.forEach { movie ->
                add(movie)
            }
        }

        val header = HeaderItem(i, entry.key)
        i++
        rowsAdapter.add(ListRow(header, listRowAdapter))
    }

    val gridHeader = HeaderItem(i, getString(R.string.more_samples))

    val gridRowAdapter = ArrayObjectAdapter(GridItemPresenter()).apply {
        add(getString(R.string.grid_view))
        add(getString(R.string.error_fragment))
        add(getString(R.string.personal_settings))
    }
    rowsAdapter.add(ListRow(gridHeader, gridRowAdapter))

    adapter = rowsAdapter

    updateRecommendations()
}

Java

@Override
public void onLoadFinished(Loader<HashMap<String, List<Movie>>> arg0,
                           HashMap<String, List<Movie>> data) {

    rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
    CardPresenter cardPresenter = new CardPresenter();

    int i = 0;

    for (Map.Entry<String, List<Movie>> entry : data.entrySet()) {
        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
        List<Movie> list = entry.getValue();

        for (int j = 0; j < list.size(); j++) {
            listRowAdapter.add(list.get(j));
        }
        HeaderItem header = new HeaderItem(i, entry.getKey());
        i++;
        rowsAdapter.add(new ListRow(header, listRowAdapter));
    }

    HeaderItem gridHeader = new HeaderItem(i, getString(R.string.more_samples));

    GridItemPresenter gridPresenter = new GridItemPresenter();
    ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(gridPresenter);
    gridRowAdapter.add(getString(R.string.grid_view));
    gridRowAdapter.add(getString(R.string.error_fragment));
    gridRowAdapter.add(getString(R.string.personal_settings));
    rowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));

    setAdapter(rowsAdapter);

    updateRecommendations();
}

Tạo chế độ xem thẻ

Ở bước này, bạn tạo trình trình bày thẻ có ngăn chứa thành phần hiển thị cho thành phần hiển thị thẻ giúp mô tả các mục nội dung đa phương tiện của bạn. Xin lưu ý rằng mỗi người trình bày chỉ được tạo một loại khung hiển thị. Nếu có hai kiểu chế độ xem thẻ, thì bạn cần có hai trình trình bày thẻ.

Trong Presenter, hãy triển khai lệnh gọi lại onCreateViewHolder() để tạo một phần tử giữ khung hiển thị dùng để hiển thị một mục nội dung:

Kotlin

private const val CARD_WIDTH = 313
private const val CARD_HEIGHT = 176

class CardPresenter : Presenter() {

    private lateinit var mContext: Context
    private lateinit var defaultCardImage: Drawable

    override fun onCreateViewHolder(parent: ViewGroup): Presenter.ViewHolder {
        mContext = parent.context
        defaultCardImage = mContext.resources.getDrawable(R.drawable.movie)
        ...

Java

@Override
public class CardPresenter extends Presenter {

    private Context context;
    private static int CARD_WIDTH = 313;
    private static int CARD_HEIGHT = 176;
    private Drawable defaultCardImage;

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent) {
        context = parent.getContext();
        defaultCardImage = context.getResources().getDrawable(R.drawable.movie);
...

Trong phương thức onCreateViewHolder(), hãy tạo chế độ xem thẻ cho các mục nội dung. Mẫu sau đây sử dụng một ImageCardView.

Khi bạn chọn một thẻ, chế độ mặc định sẽ mở rộng thẻ đó thành kích thước lớn hơn. Nếu bạn muốn chỉ định màu khác cho thẻ đã chọn, hãy gọi setSelected() như minh hoạ bên dưới:

Kotlin

    ...
    val cardView = object : ImageCardView(context) {
        override fun setSelected(selected: Boolean) {
            val selected_background = context.resources.getColor(R.color.detail_background)
            val default_background = context.resources.getColor(R.color.default_background)
            val color = if (selected) selected_background else default_background
            findViewById<View>(R.id.info_field).setBackgroundColor(color)
            super.setSelected(selected)
        }
    }
    ...

Java

...
    ImageCardView cardView = new ImageCardView(context) {
        @Override
        public void setSelected(boolean selected) {
            int selected_background = context.getResources().getColor(R.color.detail_background);
            int default_background = context.getResources().getColor(R.color.default_background);
            int color = selected ? selected_background : default_background;
            findViewById(R.id.info_field).setBackgroundColor(color);
            super.setSelected(selected);
        }
    };
...

Khi người dùng mở ứng dụng, Presenter.ViewHolder sẽ cho thấy đối tượng CardView cho các mục nội dung. Bạn cần đặt các đối tượng này để nhận tiêu điểm từ bộ điều khiển D-pad bằng cách gọi setFocusable(true)setFocusableInTouchMode(true), như minh hoạ trong mã sau:

Kotlin

    ...
    cardView.isFocusable = true
    cardView.isFocusableInTouchMode = true
    return ViewHolder(cardView)
}

Java

...
    cardView.setFocusable(true);
    cardView.setFocusableInTouchMode(true);
    return new ViewHolder(cardView);
}

Khi người dùng chọn ImageCardView, thành phần này sẽ mở rộng để hiển thị vùng văn bản bằng màu nền mà bạn chỉ định, như trong hình 1.