针对大屏设备的实战宝典  

您所在的位置:网站首页 怎么让应用全面屏显示 针对大屏设备的实战宝典  

针对大屏设备的实战宝典  

2023-12-04 04:47| 来源: 网络整理| 查看: 265

Android 提供打造 5 星级大屏应用所需的全部要素。在此实战宝典中的各个方案里,我们会选择并结合利用各种高品质要素,解决开发方面的特定问题。每个方案都包含最佳实践、优质的代码示例和分步说明,可帮助您成为大屏应用开发的高手。

星级评分

我们根据方案对大屏应用质量指南的遵循程度对其进行星级评分。

5 星 符合 1 级标准,应用在大屏设备上表现优异 4 星 符合 2 级标准,应用针对大屏设备实现了优化 3 星 符合 3 级标准,应用支持大屏设备 2 星 提供一些支持大屏设备的功能,但不符合大屏应用质量指南 1 星 满足特定用例的需求,但无法正常支持大屏设备

Chromebook 相机支持

3 星

在 Google Play 上获得 Chromebook 用户的关注。

如果您的相机应用只需基本的相机功能即可正常运行,请注意避免因为无意中指定高端手机上才有的高级相机功能而致使应用商店阻止 Chromebook 用户安装该应用。

Chromebook 内置有前置(朝向用户)的摄像头,非常适合视频会议、快照及其他应用场景。不过并非所有 Chromebook 都有后置(朝向外面)的摄像头,而且 Chromebook 上朝向用户的摄像头大多不支持自动对焦或闪光灯。

最佳实践

兼容面广的相机应用支持所有设备(无论摄像头配置如何),包括配有前置摄像头、后置摄像头和通过 USB 连接外接摄像头的设备。

为确保应用商店能让尽可能多的设备使用您的应用,请务必声明应用使用的所有相机功能,并明确指出各项功能是否为必需功能。

所需要素 CAMERA 权限:向应用授予对设备相机的使用权限 清单元素:向应用商店声明应用所使用的功能 required 属性:向应用商店指明应用在不用某项特定功能的情况下能否运行 步骤 摘要

声明 CAMERA 权限。声明可提供基本相机支持的相机功能。指明每项功能是否为必需功能。

1. 声明 CAMERA 权限

在应用清单中添加以下权限:

2. 声明基本的相机功能

在应用清单中添加以下功能:

注意:android.hardware.camera 功能特指后置(朝向外面)的摄像头。 3. 指明每项功能是否为必需功能

为 android.hardware.camera.any 功能设置 android:required="false" 以允许具有任何种类的内置或外置摄像头(或根本没有摄像头)的设备使用您的应用。

注意:如果您的应用只有在设备配有摄像头的情况下才能正常运行,请为 android.hardware.camera.any 的 required 属性指定 "true"。这样一来,没有摄像头的设备就无法使用您的应用。

对于其他功能,请设置 android:required="false",以确保没有后置摄像头、自动对焦或闪光灯功能的设备(例如 Chromebook)也能使用您发布到应用商店中的应用。

成果

Chromebook 用户可以从 Google Play 和其他应用商店下载并安装您的应用。在具有全面的相机支持的设备(例如手机)上,相机功能不会受到限制。

通过明确设置应用支持的相机功能并指定应用必需的功能,您已让自己的应用可在尽可能多的设备上使用。

其他资源

如需了解更多信息,请参阅 文档中的相机硬件功能。

限制应用在手机上的屏幕方向,但不限制其在大屏设备上的屏幕方向

2 星

您的应用在手机上的纵向模式下效果好,因此您将应用限制为仅限纵向显示。但是您发现,对于大屏设备而言,该应用在横向模式下或许可以实现更多优势。

如何同时兼顾两种场景?也就是说,如何让应用在小屏设备上仅可纵向显示,但在大屏设备上也可横向显示?

最佳实践

出色的应用会遵循用户偏好设置,例如设备屏幕方向设置。

大屏设备应用质量指南建议应用支持所有设备配置,包括纵向和横向屏幕方向、多窗口模式以及可折叠设备的折叠和展开状态。应用应针对不同的配置优化布局和界面,并且在配置发生更改时应保存及恢复状态。

此方案是一种临时性措施 - 提供些许的大屏幕支持。在您能够改进应用,使其针对所有设备配置提供全面支持之前,可以权且使用此方案。

所需要素 screenOrientation:应用清单设置,让您可以指定应用如何响应设备屏幕方向的变化 Jetpack WindowManager:让您可以确定应用窗口的尺寸和宽高比的库;向后兼容 API 级别 14 Activity#setRequestedOrientation():用于在运行时更改应用屏幕方向的方法 步骤 摘要

在应用清单中让应用默认能够响应屏幕方向变化。在运行时,确定应用窗口大小。如果应用窗口很小,则通过替换清单中的屏幕方向设置来限制应用的屏幕方向。

1. 在应用清单中指定屏幕方向设置

您可以避免声明应用清单的 screenOrientation 元素(在这种情况下,屏幕方向默认为 unspecified),或将屏幕方向设为 fullUser。如果用户没有锁定基于传感器的旋转,您的应用将支持所有设备屏幕方向。

注意:当应用在多窗口模式下运行时,screenOrientation 会被忽略(或等同于 unspecified)。因此,如果您将应用限制为仅采用一种屏幕方向,那么在多窗口模式下,应用可能无法正常运行。

使用 unspecified 和 fullUser 之间的区别虽然微不足道,但很重要。如果您未声明 screenOrientation 值,系统会选择屏幕方向,并且系统用于定义屏幕方向的政策可能会因设备而异。另一方面,指定 fullUser 与用户为设备定义的行为更相符:如果用户锁定了基于传感器的旋转,应用会遵循用户的偏好设置;否则,系统会允许设备处于四种可能的屏幕方向(纵向、横向、反向纵向或反向横向)中的任何一种。请参阅 android:screenOrientation。

2. 确定屏幕尺寸

在清单中设置为支持用户允许的所有屏幕方向后,您就能以编程方式根据屏幕尺寸指定应用的屏幕方向。

使用 Jetpack WindowManager 库的 WindowMetricsCalculator#computeMaximumWindowMetrics() 方法可获取设备屏幕尺寸(作为 WindowMetrics 对象)。窗口指标可与窗口大小类进行比较,以确定何时限制屏幕方向。

窗口大小类提供小屏幕和大屏幕之间的断点。

使用 WindowWidthSizeClass#COMPACT 和 WindowHeightSizeClass#COMPACT 断点来确定屏幕尺寸:

Kotlin /** Determines whether the device has a compact screen. **/ fun compactScreen() : Boolean { val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this) val width = metrics.bounds.width() val height = metrics.bounds.height() val density = resources.displayMetrics.density val windowSizeClass = WindowSizeClass.compute(width/density, height/density) return windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT || windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT } Java /** Determines whether the device has a compact screen. **/ private boolean compactScreen() { WindowMetrics metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this); int width = metrics.getBounds().width(); int height = metrics.getBounds().height(); float density = getResources().getDisplayMetrics().density; WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density); return windowSizeClass.getWindowWidthSizeClass() == WindowWidthSizeClass.COMPACT || windowSizeClass.getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT; } 注意: 以上示例作为 activity 的方法实现;因此,系统会在 computeMaximumWindowMetrics() 的参数中将 activity 作为 this 解除引用。 示例中使用 computeMaximumWindowMetrics() 方法代替 computeCurrentWindowMetrics(),因为应用可以在多窗口模式下启动,该模式会忽略屏幕方向设置。除非应用窗口占满整个设备屏幕,否则确定应用窗口大小并替换屏幕方向设置没有意义。

如需了解如何声明依赖项以使 computeMaximumWindowMetrics() 方法在您的应用中可用,请参阅 WindowManager。

3. 替换应用清单设置

确定设备的屏幕尺寸较小后,可以调用 Activity#setRequestedOrientation() 来替换清单的 screenOrientation 设置:

Kotlin override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestedOrientation = if (compactScreen()) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_FULL_USER ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. val container: ViewGroup = binding.container // Add a utility view to the container to hook into // View.onConfigurationChanged. This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged, // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged is // called in those scenarios. container.addView(object : View(this) { override fun onConfigurationChanged(newConfig: Configuration?) { super.onConfigurationChanged(newConfig) requestedOrientation = if (compactScreen()) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_FULL_USER } }) } Java @Override protected void onCreate(Bundle savedInstance) { super.onCreate(savedInstanceState); if (compactScreen()) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); } ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. ViewGroup container = binding.container; // Add a utility view to the container to hook into // View.onConfigurationChanged. This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged, // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged is // called in those scenarios. container.addView(new View(this) { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (compactScreen()) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); } } }); } 注意:该清单设置不会发生更改,只是被替换。

通过将逻辑添加到 onCreate() 和 View.onConfigurationChanged() 方法,您可以获取最大窗口指标,并且每当 activity 调整大小或在不同显示屏之间移动(例如在设备旋转后或者可折叠设备折叠或展开时)时,均可替换屏幕方向设置。如需详细了解何时配置会更改以及何时会导致 activity 重新创建,请参阅处理配置更改

注意:如果您没有在清单中指定 android:screenOrientation,则应将出现的 ActivityInfo.SCREEN_ORIENTATION_FULL_USER 替换为 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 以匹配默认值。 成果

现在,在小屏设备上,无论设备如何旋转,应用应该会始终保持纵向模式。在大屏设备上,该应用应支持横向模式和纵向模式。

其他资源

如果您希望升级应用以使其始终支持所有设备配置,并需要这方面的帮助,请参阅以下内容:

支持不同的屏幕尺寸 处理配置变更 保存界面状态 使用外接键盘空格键暂停和继续播放媒体

4 星

针对大屏幕的优化包括处理外接键盘输入内容的功能,例如对用户按空格键做出响应,以暂停或继续播放视频和其他媒体。这尤其适用于通常连接到外接键盘的平板电脑,以及通常附带外接键盘但可在平板电脑模式下使用的 Chromebook。

当媒体是窗口中唯一的元素(例如全屏视频播放)时,在 activity 级别或(在 Jetpack Compose 中)屏幕级别响应按键事件。

最佳实践

每当您的应用播放媒体文件时,用户都应该能够通过按实体键盘上的空格键暂停和继续播放。

所需要素 KEYCODE_SPACE:空格键的关键代码常量。

Compose

onPreviewKeyEvent:此 Modifier 让组件可在自身(或其子项之一)获得焦点时拦截硬件按键事件。 onKeyEvent:与 onPreviewKeyEvent 类似,此 Modifier 让组件可在自身(或其子项之一)获得焦点时拦截硬件按键事件。

视图

onKeyUp():当某按键被释放且不由 activity 中的 View 处理时被调用。 步骤 摘要

基于视图的应用和基于 Jetpack Compose 的应用会以类似的方式响应键盘按键操作:应用必须监听按键事件、过滤事件并响应所选的按键操作,例如按下空格键。

1. 监听键盘事件

视图

在应用的 activity 中,替换 onKeyUp() 方法:

Kotlin override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { ... } Java @Override public boolean onKeyUp(int keyCode, KeyEvent event) { ... }

此方法会在每次某个按下的键被释放时调用,因此它会针对每次按键操作触发一次。

注意:请勿使用 onKeyDown() 方法,此方法会触发多次,只要按键被按下就会触发。

Compose

使用 Jetpack Compose 时,您可以在管理按键操作的界面中使用 onPreviewKeyEvent 或 onKeyEvent 修饰符:

Column(modifier = Modifier.onPreviewKeyEvent { event -> if (event.type == KeyEventType.KeyUp) { ... } ... })

Column(modifier = Modifier.onKeyEvent { event -> if (event.type == KeyEventType.KeyUp) { ... } ... }) 注意:这两个修饰符之间的主要区别在于,相应修饰符会将未使用的事件分派到何处: onPreviewKeyEvent - 将该事件分派给其第一个子项 onKeyEvent - 将该事件分派给可组合项的父项 2. 过滤对空格键的按键操作

在 onKeyUp() 方法或 Compose onPreviewKeyEvent 和 onKeyEvent 修饰符方法中,过滤 KeyEvent.KEYCODE_SPACE 以将正确的事件发送到您的媒体组件:

视图

Kotlin if (keyCode == KeyEvent.KEYCODE_SPACE) { togglePlayback() return true } return false Java if (keyCode == KeyEvent.KEYCODE_SPACE) { togglePlayback(); return true; } return false; 注意:如果您的代码负责管理该事件,并且您不希望该事件进一步传播,则 onKeyUp 方法需要返回 true。如果您希望允许传播该事件,以便其他组件可以管理它,则返回 false。

Compose

Column(modifier = Modifier.onPreviewKeyEvent { event -> if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) { ... } ... })

Column(modifier = Modifier.onKeyEvent { event -> if (event.type == KeyEventType.KeyUp && event.key == Key.Spacebar) { ... } ... }) 成果

您的应用现在可以响应对空格键的按键操作,以暂停和继续播放视频或其他媒体。

其他资源

如需详细了解键盘事件以及如何管理这些事件,请参阅处理键盘输入。

触控笔防手掌误触

5 星

触控笔是一种可用于大屏设备上的极其高效、富有创造力的工具。但是,当使用触控笔绘图、手写或与应用互动时,用户有时会用手掌触摸屏幕。系统可能会在将其识别为意外手掌误触并予以忽略之前便将相应触摸事件报告给您的应用。

最佳实践

您的应用必须识别无关的触摸事件,并忽略这些事件。Android 通过分派 MotionEvent 对象来取消手掌触摸。针对 ACTION_CANCEL 或 ACTION_POINTER_UP 和 FLAG_CANCELED 检查该对象,以确定是否拒绝因手掌触摸而产生的手势。

所需要素 MotionEvent:表示触摸和移动事件。包含确定是否应忽略某事件所需的信息。 OnTouchListener#onTouch():接收 MotionEvent 对象。 MotionEvent#getActionMasked():返回与动作事件关联的操作。 ACTION_CANCEL:MotionEvent 常量,用于表明某手势应被撤消。 ACTION_POINTER_UP:MotionEvent 常量,用于表明除第一个指针以外的某个指针已被释放(即放弃了与设备屏幕的接触)。 FLAG_CANCELED:MotionEvent 常量,用于表明指针释放导致了一次无意中的触摸事件。已添加到 Android 13(API 级别 33)及更高版本的 ACTION_POINTER_UP 和 ACTION_CANCEL 事件。 步骤 摘要

检查分派给您的应用的 MotionEvent 对象。使用 MotionEvent API 确定事件特征:

单指针事件 - 检查是否有 ACTION_CANCEL。在 Android 13 及更高版本中,还要检查是否有 FLAG_CANCELED。 多指针事件 - 在 Android 13 及更高版本中,检查是否有 ACTION_POINTER_UP 和 FLAG_CANCELED。

响应 ACTION_CANCEL 和 ACTION_POINTER_UP/FLAG_CANCELED 事件。

警告:对于非主要多指针事件,Android 12(API 级别 32)及更低版本仅提供 ACTION_POINTER_UP。未针对手掌触摸等可取消事件而设置 FLAG_CANCELED。因此,在 Android 12 及更低版本上,应用无法确定某次触摸是有意还是无意而为之。 1. 获取动作事件对象

将 OnTouchListener 添加到您的应用中:

Kotlin val myView = findViewById(R.id.myView).apply { setOnTouchListener { view, event -> // Process motion event. } } Java View myView = findViewById(R.id.myView); myView.setOnTouchListener( (view, event) -> { // Process motion event. }); 2. 确定事件操作和标志

检查是否有 ACTION_CANCEL,它在所有 API 级别上都用于指示单指针事件。在 Android 13 及更高版本中,检查 ACTION_POINTER_UP 中是否有 FLAG_CANCELED.

Kotlin val myView = findViewById(R.id.myView).apply { setOnTouchListener { view, event -> when (event.actionMasked) { MotionEvent.ACTION_CANCEL -> { //Process canceled single-pointer motion event for all SDK versions. } MotionEvent.ACTION_POINTER_UP -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && (event.flags and MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) { //Process canceled multi-pointer motion event for Android 13 and higher. } } } true } } Java View myView = findViewById(R.id.myView); myView.setOnTouchListener( (view, event) -> { switch (event.getActionMasked()) { case MotionEvent.ACTION_CANCEL: // Process canceled single-pointer motion event for all SDK versions. case MotionEvent.ACTION_UP: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && (event.getFlags() & MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED) { //Process canceled multi-pointer motion event for Android 13 and higher. } } return true; }); 3. 撤消手势

识别出手掌触摸后,您就可以撤消相应手势在屏幕上的效果。

您的应用必须保留用户操作历史记录,以便撤消手掌触摸等意外输入。如需查看示例,请参阅增强 Android 应用中的触控笔性能支持 Codelab 中的实现基本绘图应用。

成果

现在,在 Android 13 及更高 API 级别上,您的应用可以针对多指针事件识别和拒绝手掌触摸;在所有 API 级别上,您的应用可以针对单指针事件识别和拒绝手掌触摸。

其他资源

如需了解详情,请参阅以下内容:

Android 13 功能和 API - 改善了防手掌误触 开发者指南 高级触控笔 大屏幕上的输入兼容性 Codelab - 增强 Android 应用中的触控笔性能支持 WebView 状态管理

3 星

WebView 是一个常用的组件,用于提供一种高级的状态管理系统。WebView 必须在配置更改后保持原来的状态和滚动位置。用户旋转设备或展开可折叠手机时,WebView 可能会丢失滚动位置,这会迫使用户从 WebView 顶部重新滚动到之前的滚动位置。

最佳实践

尽可能减少重新创建 WebView 的次数。WebView 善于管理其状态,并且您可以通过管理尽可能多的配置更改来利用这种特性。您的应用必须处理配置更改,因为重新创建 Activity(系统处理配置更改的方式)也会重新创建 WebView,这会导致 WebView 丢失其状态。

所需要素 android:configChanges:清单 元素的属性。列出由 activity 处理的配置更改。 View#invalidate():导致系统重新绘制 View 的方法。由 WebView 继承。 步骤 摘要

如需保存 WebView 状态,请尽可能避免重新创建 Activity,然后让 WebView 失效,以便它可以在保持其状态的同时调整大小。

1. 将配置更改添加到应用的 AndroidManifest.xml 文件中

指定由您的应用(而不是由系统)处理的配置更改,以避免重新创建 activity:

注意:尽管此配置更改列表(并非详尽无遗)可能适用于许多应用,但请务必根据用户与应用的互动方式、时长和时机,管理对您的用例最有意义的配置更改。如需为您的应用找到最佳配置组合,请参阅 android:configChanges。 2. 每当应用收到配置更改时,让 WebView 失效 Kotlin override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) webView.invalidate() } Java @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); webview.invalidate(); }

此步骤仅适用于 View 系统,因为 Jetpack Compose 无需让任何元素失效即可正确调整 Composable 元素的大小。不过,如果管理方式有误,Compose 会经常重新创建 WebView。请使用 Accompanist WebView 封装容器在 Compose 应用中保存和恢复 WebView 状态。

成果

现在,应用的 WebView 组件在遇到多种配置更改时仍可保持原来的状态和滚动位置,无论是调整大小、更改屏幕方向还是折叠和展开都不例外。

其他资源

如需详细了解配置更改及其管理方式,请参阅处理配置更改。

RecyclerView 状态管理

3 星

RecyclerView 可以使用尽可能少的图形资源显示大量数据。在 RecyclerView 滚动浏览其项列表时,RecyclerView 会重复使用已滚动到界面外的项的 View 实例,随着项在屏幕上滚动而创建新的项。但是,配置更改(例如设备旋转)可以重置 RecyclerView 的状态,迫使用户重新滚动到之前在 RecyclerView 项列表中的位置。

最佳实践

RecyclerView 应在所有配置更改期间保持其状态(特别是滚动位置)及其列表元素的状态。

所需要素 RecyclerView.Adapter#setStateRestorationPolicy():指定 RecyclerView.Adapter 在配置更改后如何恢复其状态。 ViewModel:保持 activity 或 fragment 的状态。 步骤 摘要

设置 RecyclerView.Adapter 的状态恢复政策以保存 RecyclerView 滚动位置。保存 RecyclerView 列表项的状态。将列表项的状态添加到 RecyclerView 适配器,并在列表项绑定到 ViewHolder 后恢复其状态。

1. 启用 Adapter 状态恢复政策

启用 RecyclerView 适配器的状态恢复政策,以便在遇到各种配置更改时保持 RecyclerView 的滚动位置。将政策规范添加到适配器构造函数:

Kotlin class MyAdapter() : RecyclerView.Adapter() { init { stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY } ... } Java class MyAdapter extends RecyclerView.Adapter { public Adapter() { setStateRestorationPolicy(StateRestorationPolicy.PREVENT_WHEN_EMPTY); } ... } 2. 保存有状态列表项的状态

保存复杂 RecyclerView 列表项(例如包含 EditText 元素的项)的状态。例如,如需保存 EditText 的状态,请添加类似于 onClick 处理程序的回调来捕获文本更改。在回调中,定义要保存的数据:

Kotlin input.addTextChangedListener( afterTextChanged = { text -> text?.let { // Save state here. } } ) Java input.addTextChangedListener(new TextWatcher() { ... @Override public void afterTextChanged(Editable s) { // Save state here. } });

在 Activity 或 Fragment 中声明回调。使用 ViewModel 存储状态。

3. 将列表项状态添加到 Adapter

将列表项的状态添加到 RecyclerView.Adapter。在您的主机 Activity 或 Fragment 被创建后,将项状态传递到适配器构造函数:

Kotlin val adapter = MyAdapter(items, viewModel.retrieveState()) Java MyAdapter adapter = new MyAdapter(items, viewModel.retrieveState()); 4. 在适配器的 ViewHolder 中恢复列表项状态

在 RecyclerView.Adapter 中,当您将 ViewHolder 绑定到某个项后,恢复此项的状态:

Kotlin override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { ... val item = items[position] val state = states.firstOrNull { it.item == item } if (state != null) { holder.restore(state) } } Java @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { ... Item item = items[position]; Arrays.stream(states).filter(state -> state.item == item) .findFirst() .ifPresent(state -> holder.restore(state)); } 成果

现在,您的 RecyclerView 能够恢复其滚动位置以及 RecyclerView 列表中每个项的状态。

其他资源 使用 RecyclerView 创建动态列表 高级 RecyclerView 自定义


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3