提供資訊卡檢視模式
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
使用 Compose 打造更優質的應用程式
使用 Android TV OS 適用的 Jetpack Compose,以最少的程式碼建立美觀的 UI。
本指南著重於為媒體項目建立資訊卡檢視畫面,並使用已淘汰的 Leanback UI 工具包,在瀏覽片段中呈現這些項目。如要瞭解如何在瀏覽片段中實作目錄瀏覽器,請參閱瀏覽片段指南。
BaseCardView
類別和子類別會顯示與媒體項目相關聯的中繼資料。本課程使用的 ImageCardView
類別會顯示內容的圖片,以及媒體項目的標題。
另請參閱已淘汰的
Leanback 範例應用程式
中的實作範例。
圖 1. 選取時的 Leanback 範例應用程式圖片資訊卡檢視畫面。
建立卡片呈現器
Presenter
會視需要產生檢視區塊,並將物件繫結至這些檢視區塊。在應用程式向使用者顯示內容的瀏覽片段中,您要為內容資訊卡建立 Presenter
,並將其傳遞至將內容新增至畫面的轉接器。在下列程式碼中,CardPresenter
是在 LoaderManager
的 onLoadFinished()
回呼中建立:
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();
}
建立資訊卡檢視畫面
在這個步驟中,您要使用資訊卡檢視區塊的檢視區塊持有者,建構資訊卡呈現器,說明媒體內容項目。請注意,每位簡報者只能建立一種檢視畫面類型。如果您有兩種資訊卡檢視畫面類型,則需要兩個資訊卡呈現器。
在 Presenter
中,實作 onCreateViewHolder()
回呼,建立可用於顯示內容項目的檢視區塊持有者:
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);
...
在 onCreateViewHolder()
方法中,為內容項目建立資訊卡檢視區塊。以下範例使用 ImageCardView
。
選取資訊卡後,系統會預設將其放大。如要為所選卡片指定不同顏色,請呼叫 setSelected()
,如下所示:
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);
}
};
...
使用者開啟應用程式時,Presenter.ViewHolder
會顯示內容項目的 CardView
物件。您需要呼叫 setFocusable(true)
和 setFocusableInTouchMode(true)
設定這些項目,才能透過 D-pad 控制器接收焦點,如下列程式碼所示:
Kotlin
...
cardView.isFocusable = true
cardView.isFocusableInTouchMode = true
return ViewHolder(cardView)
}
Java
...
cardView.setFocusable(true);
cardView.setFocusableInTouchMode(true);
return new ViewHolder(cardView);
}
使用者選取 ImageCardView
時,系統會展開該按鈕,並顯示您指定的背景顏色和文字區域,如圖 1 所示。
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-09-06 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-09-06 (世界標準時間)。"],[],[],null,["Build better with Compose \nCreate beautiful UIs with minimal code using Jetpack Compose for Android TV OS. \n[Compose for TV →](/training/tv/playback/compose) \n| **Warning:** The Leanback library is deprecated. Use [Jetpack Compose for\n| Android TV OS](/training/tv/playback/compose) instead.\n\nThis guide focuses on creating the card views for your media items and presenting them in the\nbrowse fragment using the deprecated Leanback UI toolkit. The implementation\nof the catalog browser in a browse fragment is detailed in the\n[Browse Fragment guide](/training/tv/playback/leanback/browse).\n\nThe [BaseCardView](/reference/androidx/leanback/widget/BaseCardView)\nclass and subclasses display the metadata associated with a media item. The\n[ImageCardView](/reference/androidx/leanback/widget/ImageCardView)\nclass used in this lesson displays an image for the content along with the media item's title.\n\nSee also the sample implementation in the deprecated\n[Leanback sample app](https://github.com/android/tv-samples/tree/main/Leanback)\n.\n\n**Figure 1.** The Leanback sample app image card view when selected.\n\nCreate a card presenter\n\nA [Presenter](/reference/androidx/leanback/widget/Presenter) generates views and binds objects to them\non demand. In the browse fragment where your app presents its content to the user, you create a\n`Presenter` for the content cards and pass it to the adapter\nthat adds the content to the screen. In the following code, the `CardPresenter` is created\nin the [onLoadFinished()](/reference/androidx/loader/app/LoaderManager.LoaderCallbacks#onLoadFinished(androidx.loader.content.Loader%3CD%3E,D))\ncallback of the [LoaderManager](/reference/androidx/loader/app/LoaderManager): \n\nKotlin \n\n```kotlin\noverride fun onLoadFinished(loader: Loader\u003cHashMap\u003cString, List\u003cMovie\u003e\u003e\u003e, data: HashMap\u003cString, List\u003cMovie\u003e\u003e) {\n rowsAdapter = ArrayObjectAdapter(ListRowPresenter())\n val cardPresenter = CardPresenter()\n\n var i = 0L\n\n data.entries.forEach { entry -\u003e\n val listRowAdapter = ArrayObjectAdapter(cardPresenter).apply {\n entry.value.forEach { movie -\u003e\n add(movie)\n }\n }\n\n val header = HeaderItem(i, entry.key)\n i++\n rowsAdapter.add(ListRow(header, listRowAdapter))\n }\n\n val gridHeader = HeaderItem(i, getString(R.string.more_samples))\n\n val gridRowAdapter = ArrayObjectAdapter(GridItemPresenter()).apply {\n add(getString(R.string.grid_view))\n add(getString(R.string.error_fragment))\n add(getString(R.string.personal_settings))\n }\n rowsAdapter.add(ListRow(gridHeader, gridRowAdapter))\n\n adapter = rowsAdapter\n\n updateRecommendations()\n}\n```\n\nJava \n\n```java\n@Override\npublic void onLoadFinished(Loader\u003cHashMap\u003cString, List\u003cMovie\u003e\u003e\u003e arg0,\n HashMap\u003cString, List\u003cMovie\u003e\u003e data) {\n\n rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());\n CardPresenter cardPresenter = new CardPresenter();\n\n int i = 0;\n\n for (Map.Entry\u003cString, List\u003cMovie\u003e\u003e entry : data.entrySet()) {\n ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);\n List\u003cMovie\u003e list = entry.getValue();\n\n for (int j = 0; j \u003c list.size(); j++) {\n listRowAdapter.add(list.get(j));\n }\n HeaderItem header = new HeaderItem(i, entry.getKey());\n i++;\n rowsAdapter.add(new ListRow(header, listRowAdapter));\n }\n\n HeaderItem gridHeader = new HeaderItem(i, getString(R.string.more_samples));\n\n GridItemPresenter gridPresenter = new GridItemPresenter();\n ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(gridPresenter);\n gridRowAdapter.add(getString(R.string.grid_view));\n gridRowAdapter.add(getString(R.string.error_fragment));\n gridRowAdapter.add(getString(R.string.personal_settings));\n rowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));\n\n setAdapter(rowsAdapter);\n\n updateRecommendations();\n}\n```\n\nCreate a card view\n\nIn this step, you build the card presenter with a view holder for the card view that describes\nyour media content items. Note that each presenter must create only one view type. If you have two\ncard view types, then you need two card presenters.\n\nIn the [Presenter](/reference/androidx/leanback/widget/Presenter), implement an\n[onCreateViewHolder()](/reference/androidx/leanback/widget/Presenter#onCreateViewHolder(android.view.ViewGroup))\ncallback that creates a view holder that can be used to display a content item: \n\nKotlin \n\n```kotlin\nprivate const val CARD_WIDTH = 313\nprivate const val CARD_HEIGHT = 176\n\nclass CardPresenter : Presenter() {\n\n private lateinit var mContext: Context\n private lateinit var defaultCardImage: Drawable\n\n override fun onCreateViewHolder(parent: ViewGroup): Presenter.ViewHolder {\n mContext = parent.context\n defaultCardImage = mContext.resources.getDrawable(R.drawable.movie)\n ...\n```\n\nJava \n\n```java\n@Override\npublic class CardPresenter extends Presenter {\n\n private Context context;\n private static int CARD_WIDTH = 313;\n private static int CARD_HEIGHT = 176;\n private Drawable defaultCardImage;\n\n @Override\n public ViewHolder onCreateViewHolder(ViewGroup parent) {\n context = parent.getContext();\n defaultCardImage = context.getResources().getDrawable(R.drawable.movie);\n...\n```\n\nIn the [onCreateViewHolder()](/reference/androidx/leanback/widget/Presenter#onCreateViewHolder(android.view.ViewGroup)) method,\ncreate a card view for content items. The following sample uses an\n[ImageCardView](/reference/androidx/leanback/widget/ImageCardView).\n\nWhen a card is selected, the default behavior expands it to a larger size. If you want to designate\na different color for the selected card, call [setSelected()](/reference/androidx/leanback/widget/BaseCardView#setSelected(boolean))\nas shown here: \n\nKotlin \n\n```kotlin\n ...\n val cardView = object : ImageCardView(context) {\n override fun setSelected(selected: Boolean) {\n val selected_background = context.resources.getColor(R.color.detail_background)\n val default_background = context.resources.getColor(R.color.default_background)\n val color = if (selected) selected_background else default_background\n findViewById\u003cView\u003e(R.id.info_field).setBackgroundColor(color)\n super.setSelected(selected)\n }\n }\n ...\n```\n\nJava \n\n```java\n...\n ImageCardView cardView = new ImageCardView(context) {\n @Override\n public void setSelected(boolean selected) {\n int selected_background = context.getResources().getColor(R.color.detail_background);\n int default_background = context.getResources().getColor(R.color.default_background);\n int color = selected ? selected_background : default_background;\n findViewById(R.id.info_field).setBackgroundColor(color);\n super.setSelected(selected);\n }\n };\n...\n```\n\nWhen the user opens your app, the [Presenter.ViewHolder](/reference/androidx/leanback/widget/Presenter.ViewHolder)\ndisplays the `CardView` objects for your content items. You need to set these to receive\nfocus from the D-pad controller by calling [setFocusable(true)](/reference/android/view/View#setFocusable(boolean))\nand [setFocusableInTouchMode(true)](/reference/android/view/View#setFocusableInTouchMode(boolean)),\nas shown in the following code: \n\nKotlin \n\n```kotlin\n ...\n cardView.isFocusable = true\n cardView.isFocusableInTouchMode = true\n return ViewHolder(cardView)\n}\n```\n\nJava \n\n```java\n...\n cardView.setFocusable(true);\n cardView.setFocusableInTouchMode(true);\n return new ViewHolder(cardView);\n}\n```\n\nWhen the user selects the [ImageCardView](/reference/androidx/leanback/widget/ImageCardView), it expands\nto reveal its text area with the background color you specify, as shown in figure 1."]]