
文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载Android TV 上的媒体应用需要让用户快速浏览、选择并播放内容卡片Card正是承载这种交互的核心视觉单元。本指南基于《Android 官方培训课程中文版》的 TV 播放应用系列聚焦 card.md 一课完整讲解如何使用 Leanback 支持库的Presenter与ImageCardView为媒体项目构建卡片视图。读完本文你将掌握从数据加载回调中组装卡片、实现onCreateViewHolder创建卡片视图、定制选中态背景色以及启用 D-pad 焦点导航的完整实战方案。卡片视图在 TV 播放应用中的定位在开始本课之前先明确它在整个 TV 播放应用构建流程中的位置。Leanback 系列的完整链路是创建目录浏览器browse.md用BrowseFragment搭建按行浏览的主布局接入数据源与适配器提供卡片视图本文为行内的每个媒体项目创建可视化的卡片创建详细信息视图details.md点击卡片后展示媒体项目的详情与操作显示正在播放卡片now-playing.md通过MediaSession在系统主屏展示当前播放状态。上一课已经用BrowseFragment建好了目录框架并通过ArrayObjectAdapter、ListRow、HeaderItem等对象把媒体数据组织成分类行 行内条目的层级结构。本课要解决的正是这一环如何把行内的一个个媒体条目渲染成用户能看到、能聚焦、能选中的卡片。认识卡片视图BaseCardView 与 ImageCardViewLeanback 库android.support.v17.leanback.widget包为 TV 界面提供了一套专为十英尺 UI远距离观看、遥控器操作设计的组件。其中BaseCardView是所有卡片视图的基类负责显示与媒体项目关联的元数据例如标题、描述、状态信息等ImageCardView继承自BaseCardView是本节的核心组件——它在卡片上同时呈现图像与标题文字图像区展示媒体项目的预览图海报或截图下方info_field区域展示标题、副标题等文字信息。之所以使用卡片而非简单的TextView是因为卡片在电视大屏上能以图文结合、尺寸规整的方式呈现媒体内容配合统一的焦点高亮效果让用户在一屏内快速扫描大量内容。创建卡片呈现者CardPresenterPresenter 的职责在 Leanback 的呈现模型中Presenter负责生成视图并把数据对象与视图绑定起来。它把数据 → 视图的渲染逻辑从 Activity / Fragment 中剥离出来使同一套卡片样式可以被任意数据驱动复用。Presenter是一个抽象类核心生命周期由三个抽象方法构成对应方法三件套在 browse.md 的StringPresenter示例中也有完整体现方法职责onCreateViewHolder(ViewGroup parent)创建并返回承载视图的ViewHolder只做视图的构建与初始化onBindViewHolder(ViewHolder viewHolder, Object item)把具体数据对象绑定到视图上更新视图内容onUnbindViewHolder(ViewHolder viewHolder)解绑视图释放资源如无特殊需求可留空关键约束每个 Presenter 只能对应一种视图类别。如果应用需要两种不同的卡片样式就必须分别创建两个不同的 Presenter 并在适配器中配置。在数据加载回调中组装卡片卡片呈现者通常在数据加载完成后被创建并注入适配器。下面这段来自 card.md 的完整代码演示了在LoaderManager.LoaderCallbacks.onLoadFinished()回调中构建带卡片的行式适配器Override public void onLoadFinished(LoaderHashMapString, ListMovie arg0, HashMapString, ListMovie data) { mRowsAdapter new ArrayObjectAdapter(new ListRowPresenter()); CardPresenter cardPresenter new CardPresenter(); int i 0; for (Map.EntryString, ListMovie entry : data.entrySet()) { ArrayObjectAdapter listRowAdapter new ArrayObjectAdapter(cardPresenter); ListMovie list entry.getValue(); for (int j 0; j list.size(); j) { listRowAdapter.add(list.get(j)); } HeaderItem header new HeaderItem(i, entry.getKey(), null); i; mRowsAdapter.add(new ListRow(header, listRowAdapter)); } HeaderItem gridHeader new HeaderItem(i, getString(R.string.more_samples), null); 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)); mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter)); setAdapter(mRowsAdapter); updateRecommendations(); }逐段拆解这段代码的组装逻辑最外层适配器mRowsAdapter new ArrayObjectAdapter(new ListRowPresenter())。ListRowPresenter负责把每个ListRow一整行渲染出来是最外层行容器的 Presenter行内适配器new ArrayObjectAdapter(cardPresenter)为本课的CardPresenter创建行内条目容器随后把该分类下的每个Movie对象逐一add()进去。这一层的 Presenter 决定了行内每个条目以什么视图呈现——正是我们要创建的卡片分类标题new HeaderItem(i, entry.getKey(), null)为每行指定分类名如电影类型、播放列表名称配合new ListRow(header, listRowAdapter)把标题 行内卡片适配器组合成完整的一行附加功能行代码末尾还用GridItemPresenter创建了一行由普通字符串构成的网格项如网格视图错误页面个人设置入口演示了同一个mRowsAdapter中可以混排不同 Presenter 驱动的行组装完成后通过setAdapter(mRowsAdapter)交给浏览 Fragment 渲染并调用updateRecommendations()同步推荐数据。实现 onCreateViewHolder创建卡片视图Presenter的三件套中第一步是在onCreateViewHolder()里创建承载内容的ViewHolder与卡片视图。下面这段代码展示了CardPresenter的关键初始化逻辑Override public class CardPresenter extends Presenter { private Context mContext; private static int CARD_WIDTH 313; private static int CARD_HEIGHT 176; private Drawable mDefaultCardImage; Override public ViewHolder onCreateViewHolder(ViewGroup parent) { mContext parent.getContext(); mDefaultCardImage mContext.getResources().getDrawable(R.drawable.movie); ...几个值得注意的细节卡片尺寸常量示例中CARD_WIDTH 313、CARD_HEIGHT 176像素从比例上看313/176 ≈ 1.78接近 16:9 的宽幅卡片与 TV 媒体内容的宽幅截图比例吻合实际开发时应根据目标屏幕密度与设计稿调整默认占位图mDefaultCardImage mContext.getResources().getDrawable(R.drawable.movie)为还没有加载出真实图像的卡片准备默认图保证渲染过程中不出现空白mContext取自parent.getContext()即浏览界面的 Context后续创建视图、读取资源都会用到。接着在onCreateViewHolder()中创建卡片视图本体。示例使用的是ImageCardViewImageCardView cardView new ImageCardView(mContext) { Override public void setSelected(boolean selected) { int selected_background mContext.getResources().getColor(R.color.detail_background); int default_background mContext.getResources().getColor(R.color.default_background); int color selected ? selected_background : default_background; findViewById(R.id.info_field).setBackgroundColor(color); super.setSelected(selected); } };这段代码有两层含义Leanback 的默认选中行为BaseCardView在卡片被选中时默认会放大展开scale-up产生视觉反馈自定义选中配色通过重写setSelected(boolean)在选中与未选中之间切换卡片文字信息区R.id.info_field的背景色——选中时使用detail_background高亮色未选中时恢复default_background。注意重写方法内部必须调用super.setSelected(selected)否则基类的放大展开等默认行为将失效。启用 D-pad 焦点导航TV 没有触摸屏用户完全依靠遥控器上的D-pad方向键移动焦点。因此卡片视图必须显式声明自己可以接收焦点cardView.setFocusable(true); cardView.setFocusableInTouchMode(true); return new ViewHolder(cardView);setFocusable(true)使视图可被 D-pad 的上下左右键移动焦点并选中setFocusableInTouchMode(true)保证在 TV 这种以触控模式事件模拟方向键输入的环境下焦点同样生效最后用new ViewHolder(cardView)把卡片视图包装成Presenter.ViewHolder返回。这一可聚焦模式与上一课 browse.md 中StringPresenter对TextView的处理完全一致textView.setFocusable(true)、textView.setFocusableInTouchMode(true)是 Leanback 中所有可交互视图的统一约定。当用户用 D-pad 选中ImageCardView时卡片会以我们指定的颜色背景展开文字内容同时默认放大效果如下图所示综合接线卡片如何在浏览界面中呈现回顾整条数据流卡片视图的呈现链路可以概括为Loader 加载数据 → onLoadFinished 中创建 CardPresenter → ArrayObjectAdapter(cardPresenter) 逐条 add(Movie) → ListRow(header, listRowAdapter) 组装分类行 → mRowsAdapter 交给 BrowseFragment 的 setAdapter() → ListRowPresenter 渲染每行CardPresenter 渲染行内每张卡片 → D-pad 聚焦 → setSelected 切换高亮补充两个实战要点一个 Presenter 对应一种视图如果需要横版海报卡片 竖版封面卡片两种样式必须写两个 Presenter通过ClassPresenterSelector按数据类分发该模式在下一课 details.md 的ClassPresenterSelector中会再次出现数据与视图分离onBindViewHolder阶段才把Movie对象写入视图因此视图创建一次即可复用滚动时仅做绑定更新这与 browse.md 中StringPresenter.onBindViewHolder的写法相互印证。与后续课程的衔接卡片视图完成后TV 播放应用的浏览体验已经成型。接下来两课在此基础上继续深入创建详细信息视图为媒体项目创建DetailsFragment详情页展示描述、预览图与购买/播放等操作显示正在播放卡片用MediaSession把当前播放状态呈现在系统主屏的正在播放卡片上。此外若需在浏览过程中动态更新背景图以增强视觉趣味可参考 browse.md 中BackgroundManager与OnItemViewSelectedListener的用法将选中监听器与本课的卡片焦点模型结合使用。赞分享文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载相关推荐Android TV 播放应用构建指南基于 Leanback 库的浏览、卡片、详情与正在播放实现Android TV 播放应用构建指南基于 Leanback 库的浏览、卡片、详情与正在播放实现 本指南基于「Android官方培训课程中文版」仓库中 tv/文档教程移动开发Android TV 播放应用开发使用 Leanback BrowseFragment 构建媒体目录浏览器android-training-course-in-chineseAndroid TV 播放应用开发使用 Leanback BrowseFragment 构建媒体目录浏览器android training course i文档教程移动开发Android TV 后台媒体播放使用 MediaSession 实现主屏幕「正在播放」卡片Android TV 后台媒体播放使用 MediaSession 实现主屏幕「正在播放」卡片 本文基于仓库 tv/playback/now playing.m文档教程移动开发上一篇YOLOv10 神经网络模块工具函数深度解析ultralytics/nn/modules/utils.py 五大核心函数与实现原理下一篇FrankenPHP 原生支持 HTTP 103 Early Hints用 PHP 预加载资源、加速页面渲染的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考