鸿蒙开发实例 | 可复用列表项的ListContainer

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 简短的列表可以通过定向布局实现,但是如果列表项非常多,那么使用定向布局就不合适了。与许多其他的移动开发技术一样,鸿蒙操作系统也提供了可复用列表项的列表组件,这就是本篇文章要介绍的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所示。

dd5d673f53245e93ee8dd4be418152f3.png

■ 图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"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="vertical">
    <Text
        ohos: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"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="vertical">
    <ListContainer
        ohos:id="$+id:list_container"
        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;
@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_slice_list_container);
    //初始化列表数据对象
    mNumbers = new ArrayList<>();
    for (int i = 0; i < 1000; i++) {
        mNumbers.add(i + 1);
    }
    //获取ListContainer对象
    mListContainer = (ListContainer) findComponentById(ResourceTable.Id_list_container);
    //为ListContainer对象设置RecycleItemProvider
    mListContainer.setItemProvider(new RecycleItemProvider() {
        @Override
        public int getCount() {
            //列表项数
            return mNumbers.size();
        }
        @Override
        public Object getItem(int i) {
            //当前列表项的数据
            return mNumbers.get(i);
        }
        @Override
        public long getItemId(int i) {
            //当前列表项ID
            return i;
        }
        @Override
        public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
            //列表项用户界面 (如果可以复用之前的界面,则直接复用)
            DirectionalLayout layout = (DirectionalLayout) component;
            if (layout == null) {
                //如果之前的界面为空,则创建新的列表项用户界面
                layout = (DirectionalLayout) LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_recycle_item, null, false);
            }
            //获取列表项中的文本组件
            Text text = (Text) layout.findComponentById(ResourceTable.Id_item_text);
            //设置列表项数据
            text.setText("当前数据:" + getItem(i).toString());
            //返回该列表项用户界面
            return layout;
        }
    });
}


在上面的代码中,创建了包含从1到1000整型数据的列表mNumbers作为列表项的数据。在RecycleItemProvider的getCount()方法中,返回了这个列表的长度1000; 在getItem(int i)方法中,返回了当前列表项的整数值; 在getItemId(int i)方法中,返回了当前列表项的ID。此时,在getComponent方法中,即可通过getItem(i)方法获取这个列表项所需要的整数值。


在上面的getComponent方法中,存在一个非常典型的判断方法,即判断可复用组件component是否为空。如果该对象为空,则只能再创建一个新的列表项组件。这充分体现了ListContainer 按需创建组件的优势。随后,通过列表项组件layout 的findComponentById方法获取列表项文本组件,并设置了相应的文本内容。上述代码的最终显示效果如图2所示。

image.png

■ 图2 列表组件ListContainer的显示效果


滑动列表,可以发现列表项中的【当前数据:××】(××为具体数字)可以从1到1000变化,整个过程丝滑流畅。


注意: 具有Android开发经验的开发者可以发现,ListContainer相对于Android中的RecyclerView,而RecycleItemProvider的功能非常类似于Android中的Adapter。唯一不同的是,鸿蒙操作系统中不再有ViewHolder概念了。不过对于复杂的需求来讲,开发者也可以创建类似于ViewHolder的类(不继承任何鸿蒙类),专门用于管理用户界面。这样一来,即可将用户界面管理的功能从RecycleItemProvider中解耦出去,在复杂需求场景下还是很实用的。


目录
相关文章
|
IDE JavaScript API
HarmonyOS开发第一步,熟知开发工具DevEco Studio
本文主要以常见的功能点作为概述希望可以帮助到学习HarmonyOS的开发者。
459 0
|
开发框架 开发者 JavaScript
HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 三)
子组件中被@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。
|
1月前
|
JavaScript 前端开发 小程序
基于js开发快速学习鸿蒙基础
【8月更文挑战第26天】
37 1
|
2月前
|
存储 开发框架 安全
鸿蒙 HarmonyOS NEXT星河版APP应用开发-阶段一
HarmonyOS NEXT星河版的应用开发标志着华为分布式操作系统的全新篇章,它聚焦于打造原生精致、易用、流畅、安全、智能和互联的极致体验。开发者可以利用其先进的API和工具集,如DevEco Studio,构建高性能、跨设备无缝协同的应用程序,从而充分利用HarmonyOS的分布式能力,为用户带来一致且丰富的多场景数字生活体验。随着“学习强国”、岚图汽车、中国电信等知名企业和应用的加入,鸿蒙生态正迅速扩展,引领着原生应用开发的新趋势。
91 3
鸿蒙 HarmonyOS NEXT星河版APP应用开发-阶段一
|
2月前
|
人工智能 搜索推荐 数据可视化
鸿蒙应用实践:利用扣子API开发起床文案生成器
本文将使用扣子(coze)智能体API开发一个起床文案生成器,用于自己的鸿蒙应用中生成”千人千面“的起床文案。
74 0
|
4月前
|
JavaScript API
鸿蒙开发接口UI界面:【@ohos.mediaquery (媒体查询)】
鸿蒙开发接口UI界面:【@ohos.mediaquery (媒体查询)】
57 1
HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 四)
被@Observed装饰的类,可以被观察到属性的变化;子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中是属性,这个属性同样也需要被@Observed装饰。单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。
|
人工智能 JSON API
HarmonyOS学习路之开发篇—AI功能开发(语音识别)
语音识别功能提供面向移动终端的语音识别能力。它基于华为智慧引擎(HUAWEI HiAI Engine)中的语音识别引擎,向开发者提供人工智能应用层API。该技术可以将语音文件、实时语音数据流转换为汉字序列,准确率达到90%以上(本地识别95%)。
|
4月前
|
前端开发 JavaScript 开发者
鸿蒙2.0!用 JavaScript 开发鸿蒙应用
鸿蒙2.0!用 JavaScript 开发鸿蒙应用
123 0
|
4月前
|
人工智能 安全 开发者
中国移动APP启动鸿蒙原生应用开发,鸿蒙生态迎来通信领域民生应用
近日,在“鸿蒙生态全面合作签约暨开发启动仪式“上,中国移动通信有限公司在线营销服务中心宣布将与鸿蒙生态在技术互补、成果共享、商业共赢等方向进行合作,以共同推动鸿蒙智能化的移动开放生态业务发展,并正式启动中国移动APP鸿蒙原生应用及元服务开发。