提供卡片视图
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
使用 Compose 构建更出色的应用
使用适用于 Android TV OS 的 Jetpack Compose,只需极少的代码即可创建精美的界面。
<ph type="x-smartling-placeholder">
</ph>
Compose for TV →
在上一课中,您创建了一个在浏览 fragment 中实现的目录浏览器,
,显示媒体项列表。在本课中,您将为媒体项创建卡片视图
呈现它们。
BaseCardView
类及其子类显示与媒体项关联的元数据。通过
ImageCardView
类会显示内容的图片以及媒体项的标题。
另请参阅
<ph type="x-smartling-placeholder"></ph>
Leanback 示例应用
,了解所有最新动态。
图 1. 选中后的 Leanback 示例应用图像卡片视图。
创建卡片 Presenter
Presenter
生成视图并向视图绑定对象
。在应用向用户呈现内容的浏览 fragment 中,您可以创建一个
为内容卡片使用 Presenter
并将其传递给适配器
用于将内容添加到屏幕的按钮。在以下代码中,创建了 CardPresenter
在 onLoadFinished()
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();
}
创建卡片视图
在此步骤中,您将为卡片视图构建卡片 Presenter 和视图持有者,
媒体内容。请注意,每个 Presenter 只能创建一个视图类型。如果您有两个
卡片视图类型,则需要两个卡片 Presenter。
在 Presenter
中,实现一个
onCreateViewHolder()
创建可用于显示内容项的 ViewHolder 的回调:
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)
,
如以下代码所示:
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 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-27。
[null,null,["最后更新时间 (UTC):2025-07-27。"],[],[],null,["# Provide a card view\n\nBuild 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\nIn the previous lesson, you created a catalog browser, implemented in a browse fragment, that\ndisplays a list of media items. In this lesson, you create the card views for your media items and\npresent them in the browse fragment.\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\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-----------------------\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\n### Kotlin\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\n### Java\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------------------\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\n### Kotlin\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\n### Java\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\n### Kotlin\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\n### Java\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\n### Kotlin\n\n```kotlin\n ...\n cardView.isFocusable = true\n cardView.isFocusableInTouchMode = true\n return ViewHolder(cardView)\n}\n```\n\n### Java\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."]]