鸿蒙开发实例 | 可复用列表项的 ListContainer
简短的列表可以通过定向布局实现,但是如果列表项非常多,那么使用定向布局就不合适了。与许多其他的移动开发技术一样,鸿蒙操作系统也提供了可复用列表项的列表组件,这就是本篇文章要介绍的 ListContainer。
01、可复用列表项的 ListContainer 简短的列表可以通过定向布局实现,但是如果列表项非常多,则使用定向布局就不合适了。例如,需要创建 100 个列表项的列表,那么用定向布局实现至少需要创建 100 个以上的组件了。然而,限于设备屏幕大小的限制,绝大多数组件不会显示在屏幕上,却会占据大量的内存资源,甚至造成应用“闪退”。
与许多其他的移动开发技术一样,鸿蒙操作系统也提供了可复用列表项的列表组件 ListContainer。
注意: 在 Android 和 iOS 系统中,均提供了与 ListContainer 类似的可复用列表项的列表组件。在 Android 系统中,这种组件被称为 RecyclerView; 在 iOS 系统中,这种组件被称为 UITableView。
ListContainer 继承于 ComponentContainer,属于布局的一种。在 ListContainer 中,每个列表项都是一个组件或者子布局,即列表项组件。不过,ListContainer 非常“吝啬”。
例如,利用 ListContainer 实现具有 100 个列表项的列表,ListContainer 绝对不会实实在在地创建 100 个组件,而是仅创建屏幕当前能够显示的列表项组件。
例如,当前的设备屏幕只能够显示 6 个列表项,那么 ListContainer 只创建 6 个列表项组件。当用户上下滑动到其他的列表项时,被滑出去的列表项组件会被新的列表项复用,重新更换数据后再次进入用户的视野,如图 1 所示。
■ 图 1 “吝啬”的列表组件 ListContainer
在图 1 中,Item 1 组件被滑出列表,随后被 ListContainer“换装”填入新的数据后再次从列表底部重新进入 ListContainer。Item 1 组件和 Item 7 组件实际上是 1 个组件,组件还是原来的组件,只不过数据已经不是原来的数据了。这种按需创建组件的思想对于应用程序能够流畅稳定地运行非常重要。这么说来,ListContainer 就像一个掌管着系统资源的大臣,时时刻刻打着精细的算盘,用最少的内存资源来干更多事情。
那么,我们应该如何来使用 ListContainer 呢? 实际上,ListContainer 已经封装好复用列表项的机制了,不需要开发者过多操心。作为开发者,只需为 ListContainer 提供需要显示的列表项所需要的数据和组件就可以了,而这项工作就全权交给 RecycleItemProvider 类完成了。RecycleItemProvider 是一个抽象类,开发者在使用它之前需要至少实现以下 4 种方法。
(1) getCount(): 提供列表项数量。
(2) getItem(int i): 提供当前列表项的数据。
(3) getItemId(int i): 提供当前列表项 ID。
(4) getComponent(int id,Component cpt,ComponentContainer ctn): 创建组件与数据绑定,即创建属于这个列表项的组件,然后绑定该列表项数据。在这种方法中,id 表示这个列表项 ID,cpt 对象为上一次这个列表项的组件对象。作为开发者可以直接复用这个组件对象,当然也可以创建一个新的组件对象。ctn 是 cpt 组件的父布局对象。
接下来,演示 ListContainer 和 RecycleItemProvider 的具体使用方法。
首先,通过布局文件(recycle_item.xml)创建列表项的用户界面,代码如下:
/javaUI/entry/src/main/resources/base/layout/recycle_item.xml<?xml version="1.0" encoding="utf-8"?><DirectionalLayoutxmlns:ohos="http://schemas.huawei.com/res/ohos"ohos:height="match_content"ohos:width="match_parent"ohos:orientation="vertical"><Textohos:id="$+id:item_text"ohos:height="match_content"ohos:width="match_parent"ohos:margin="4vp"ohos:text_size="16fp"ohos:text_alignment="center"/></DirectionalLayout>
这个列表项非常简单,仅仅显示了一个文本组件,用于显示列表项数据,但是,这个用户界面与之前介绍的 AbilitySlice 界面不同,这个列表项界面仅仅显示在屏幕的某一个部位,因此不能使用之前的 setUIContent 方法了。
此时,需要 LayoutScatter 类来解析这个布局文件,LayoutScatter 并不能直接被初始化,需要通过其 getInstance(Context context)方法获取,其中 content 为当前的上下文对象。获取 LayoutScatter 对象后,通过其 parse(int xmlId,ComponentContainer root,boolean attachToRoot)方法即可解析所需要的 XML 布局文件,并且转换为组件对象。在 parse 方法中,xmlId 表示需要解析的布局资源 ID。当 attachToRoot 参数为 true 时,可以将解析出来的组件对象自动添加到 root 布局中,但是,在绝大多数情况下并不需要这么做,此时传递 root 参数为 null,传递 attachToRoot 参数为 false 即可。
因此,通过以下代码即可将上面创建的列表项组件转换为 DirectionalLayout 对象,代码如下:
LayoutScatter scatter = LayoutScatter.getInstance(getContext());DirectionalLayout layout = scatter.parse(ResourceTable.Layout_recycle_item, null, false);除了定义列表项界面以外,还需要在 AbilitySlice 中定义 ListContainer 对象。在布局文件中定义一个 ListContainer,代码如下:
//JavaUI/entry/src/main/resources/base/layout/slice_list_container.xml<?xml version="1.0" encoding="utf-8"?><DirectionalLayoutxmlns:ohos="http://schemas.huawei.com/res/ohos"ohos:height="match_parent"ohos:width="match_parent"ohos:orientation="vertical">
</DirectionalLayout>
接下来,就可以在相应的 AbilitySlice 中通过 RecycleItemProvider 实现一个列表了,代码如下:
//JavaUI/entry/src/main/java/com/example/javaui/slice/ListContainerAbilitySlice.java//ListContainer 对象 private ListContainer mListContainer;//列表数据(1-1000 整型值)private List<Integer> mNumbers;
@Overridepublic void onStart(Intent intent) {super.onStart(intent);super.setUIContent(ResourceTable.Layout_slice_list_container);
}
在上面的代码中,创建了包含从 1 到 1000 整型数据的列表 mNumbers 作为列表项的数据。在 RecycleItemProvider 的 getCount()方法中,返回了这个列表的长度 1000; 在 getItem(int i)方法中,返回了当前列表项的整数值; 在 getItemId(int i)方法中,返回了当前列表项的 ID。此时,在 getComponent 方法中,即可通过 getItem(i)方法获取这个列表项所需要的整数值。
在上面的 getComponent 方法中,存在一个非常典型的判断方法,即判断可复用组件 component 是否为空。如果该对象为空,则只能再创建一个新的列表项组件。这充分体现了 ListContainer 按需创建组件的优势。随后,通过列表项组件 layout 的 findComponentById 方法获取列表项文本组件,并设置了相应的文本内容。上述代码的最终显示效果如图 2 所示。
■ 图 2 列表组件 ListContainer 的显示效果
滑动列表,可以发现列表项中的【当前数据:××】(××为具体数字)可以从 1 到 1000 变化,整个过程丝滑流畅。
注意: 具有 Android 开发经验的开发者可以发现,ListContainer 相对于 Android 中的 RecyclerView,而 RecycleItemProvider 的功能非常类似于 Android 中的 Adapter。唯一不同的是,鸿蒙操作系统中不再有 ViewHolder 概念了。不过对于复杂的需求来讲,开发者也可以创建类似于 ViewHolder 的类(不继承任何鸿蒙类),专门用于管理用户界面。这样一来,即可将用户界面管理的功能从 RecycleItemProvider 中解耦出去,在复杂需求场景下还是很实用的。
评论