Hướng dẫn này tập trung vào việc tạo khung hiển thị thẻ cho các mục nội dung nghe nhìn và trình bày các mục đó trong mảnh duyệt qua bằng bộ công cụ giao diện người dùng Leanback không dùng nữa. Việc triển khai trình duyệt danh mục trong một mảnh duyệt xem được trình bày chi tiết trong Hướng dẫn về mảnh duyệt xem.
Lớp BaseCardView
và các lớp con hiển thị siêu dữ liệu được liên kết với một mục nội dung nghe nhìn. Lớp ImageCardView
được 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 nghe nhìn.
Bạn cũng có thể xem ví dụ về cách triển khai trong ứng dụng mẫu Leanback không dùng nữa.

Hình 1. Chế độ xem thẻ hình ảnh của ứng dụng mẫu Leanback khi được chọn.
Tạo người trình bày thẻ
Presenter
tạo các thành phần hiển thị và liên kết các đối tượng với các thành phần hiển thị đó theo yêu cầu. Trong mảnh duyệt tìm nơi ứng dụng của bạn trình bày nội dung cho người dùng, bạn sẽ tạo một Presenter
cho thẻ nội dung và truyền thẻ đó đế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ẻ
Trong bước này, bạn sẽ tạo trình bày thẻ bằng một trình giữ khung hiển thị cho khung hiển thị thẻ mô tả các mục nội dung nghe nhìn. Xin lưu ý rằng mỗi presenter chỉ được tạo một loại khung hiển thị. Nếu có 2 loại khung hiển thị thẻ, thì bạn cần 2 trình bày thẻ.
Trong Presenter
, hãy triển khai một lệnh gọi lại onCreateViewHolder()
để tạo một trình giữ khung hiển thị có 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 một khung hiển thị thẻ cho các mục nội dung. Mẫu sau đây sử dụng ImageCardView
.
Khi bạn chọn một thẻ, hành vi 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ột màu khác cho thẻ đã chọn, hãy gọi setSelected()
như minh hoạ ở đây:
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 của bạn, Presenter.ViewHolder
sẽ hiển thị các đối tượng CardView
cho các mục nội dung của bạn. Bạn cần đặt các giá trị này để nhận tiêu điểm từ bộ điều khiển D-pad bằng cách gọi setFocusable(true)
và setFocusableInTouchMode(true)
, như 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
, nút này sẽ mở rộng để hiển thị vùng văn bản có màu nền mà bạn chỉ định, như minh hoạ trong hình 1.