HarmonyOS 鸿蒙Next中「3.4 熟知的列表」闯荡HAP之单一列表和组装列表

HarmonyOS 鸿蒙Next中「3.4 熟知的列表」闯荡HAP之单一列表和组装列表 在一个文件夹里会罗列出很多个子文件夹或者文件,包含文件名、文件大小、文件修改日期、文件类型等;

在一个内容网站里会罗列出很多条内容,或许还要翻页,包含文章标题、文章作者、发表时间、浏览量等;

在一个图册网站,里面会罗列出很多图集或者图片,包含图集名称、图集作者等;

在一个音乐播放器的具体某类歌曲中,会罗列出很多歌曲,包含歌名、作者、所属歌集、时长等;

还有很多想类似的情况,这里就不一一列举了。通过上面四个场景,我们可以发现一个共同的特点,它们都有很多条数据,每个场景中数据的属性是相同的。这就让我想起了在学习Java 的数组时,对于一维数组,其元素的类型是相同的,你不可能定义了一个整形的数组,向里面添加了字符串类型的元素,这是不行的。假如我们需要做一个新闻类的展示界面,那么我们的数据中,每个元素中的属性必须是一样的。比如我们的元素属性包含标题、作者、内容摘要、封面图、发布时间、浏览记录、点赞量、评论量,但是在这个列表中存在一个特殊的元素,它的属性为歌曲名称、作者、歌集、时长,那么我们在展示这个数据集的时候,会出现什么问题呢(这里不做详细说明了,也许你已经知道答案是什么了)?

对于ListContainer组件的理论不在这里做赘述了,官文已经说得很明白了,本节将结合OkHttp插件,来使用ListContainer组件做一个简单的新闻展示Demo。

在开始复杂的列表展示页之前,我们先来做一个简单的列表展示,在学习Android的时候,列表有个展示水果的示例,我将在HarmonyOS智慧屏上实现这个小示例。

一、单一的列表

1、在layout目录下新建fruit_layout.xml文件,并创建ListContainer组件,代码如下:

<?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:fruit_list"
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:layout_alignment="horizontal_center"/>
</DirectionalLayout>

2、接着在layout目录新建element_layout.xml文件,作为ListContainer组件的子布局,代码如下:

<?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:background_element="$graphic:background_element"
    ohos:bottom_margin="4vp"
    ohos:orientation="vertical">
    <Text
        ohos:id="$+id:element_index"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:padding="4vp"
        ohos:text_size="30fp"
        ohos:layout_alignment="center"/>
</DirectionalLayout>

3、组建一个类型为String的List列表,最终呈现在UI界面上。

List<String> fruits = new ArrayList<>();
fruits.add("苹果");
fruits.add("橘子");
fruits.add("橙子");
fruits.add("香蕉");
fruits.add("梨");
fruits.add("桃子");
fruits.add("苹果梨");
fruits.add("香蕉梨");
fruits.add("冬桃");
fruits.add("红葡萄");
fruits.add("紫葡萄");
fruits.add("黑葡萄");

4、ListContainer组件的每一行元素可以是不相同的数据,因此需要适配不同的数据结构,使其能够添加到ListContainer组件中,并以列表的形式呈现在UI界面上。ListContainer组件提供了setItemProvider(BaseItemProvider itemProvider)方法,用于设置要显示的ListContainer组件对象。创建FruitElementProvider类,并继承BaseItemProvider,重写其中的方法。

package com.ming.harmonyos.newsapp.domain;

import com.ming.harmonyos.newsapp.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.components.*;

import java.util.List;

public class FruitElementProvider extends BaseItemProvider {

    private List<String> list;

    private AbilitySlice slice;

    public FruitElementProvider(List<String> fruits, AbilitySlice slice) {
        this.list = fruits;
        this.slice = slice;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int i) {
        return list.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
        Component cpt = component;
        if (cpt == null) {
            cpt = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_element_layout, null, false);
        }
        String fruit = list.get(i);
        Text text = (Text) cpt.findComponentById(ResourceTable.Id_element_index);
        text.setText(fruit);
        return cpt;
    }
}

5、在MainAbility中适配ListContainer的数据结构,并添加点击事件。

ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_fruit_list);
List<String> fruits = new ArrayList<>();
fruits.add("苹果");
fruits.add("橘子");
fruits.add("橙子");
fruits.add("香蕉");
fruits.add("梨");
fruits.add("桃子");
fruits.add("苹果梨");
fruits.add("香蕉梨");
fruits.add("冬桃");
fruits.add("红葡萄");
fruits.add("紫葡萄");
fruits.add("黑葡萄");
FruitElementProvider fruitElementProvider = new FruitElementProvider(fruits, this);
listContainer.setItemProvider(fruitElementProvider);
listContainer.setItemClickedListener((listContainer1, component, position, id) -> {
    String item = (String) listContainer1.getItemProvider().getItem(position);
    new ToastDialog(getContext())
        .setText("点击了:" + item)
        // Toast显示在界面中间
        .setAlignment(LayoutAlignment.CENTER)
        .show();
});

6、运行查看效果。

二、组合复杂的列表

1、和单一列表不同之处在于元素的显示和元素的属性。单一列表中我使用了一个List<String>,复杂的列表中,我将根据请求API接口返回的数据类型进行数据结构的组装。在这之前我先要说说OkHttp如何引入,以及需要授予那些权限。

1)首先我们在build.gradle中引入OkHttp(本节并不是对OkHttp做详细讲解,这里只是简单的使用)的版本,并点击窗口上的Sync Now进行同步下载。

implementation("com.squareup.okhttp3:okhttp:4.9.0")

2)在config.json中配置INTENT权限。

{
    "reqPermissions": [
        {
            "name": "ohos.permission.INTERNET",
            "usedScene": {
                "ability": [
                    "com.ming.harmonyos.newsapp.MainAbility"
                ],
                "when": "always"
            }
        }
    ]
}

3)在MainAbilitySlice中实例化OkHttpClient对象,并封装它的GET调用方法。

private OkHttpClient client = new OkHttpClient();

private String run(String url) throws IOException {
    Request request = new Request.Builder()
        .url(url)
        .build();

    try (Response response = client.newCall(request).execute()) {
        return response.body().string();
    }
}

2、做好上面的准备之后,我使用天行数据的每日简报API接口。先看一下调用接口返回的参数:

参数截图

3、我们根据返回的参数来构建我们的列表元素类。

public class News {
    //新闻标题
    private String title;
    //简报内容
    private String digest;
    //简报封面
    private String imgsrc;
    //简报链接
    private String url;
    //简报来源
    private String source;
    //新闻时间
    private String mtime;

    //getter & setter
}

4、在layout目录新建news_element_layout.xml文件,作为ListContainer组件的子布局,代码如下:

<?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:bottom_margin="4vp"
    ohos:orientation="vertical">

    <DirectionalLayout
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:background_element="$graphic:background_element"
        ohos:orientation="horizontal">
        <Image
            ohos:id="$+id:news_imgsrc"
            ohos:image_src="$media:icon"
            ohos:height="100vp"
            ohos:width="100vp"/>

        <DirectionalLayout
            ohos:height="match_parent"
            ohos:width="match_parent">
            <Text
                ohos:id="$+id:news_title"
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:weight="1"
                ohos:text="我是标题"
                ohos:text_size="20fp"/>
            <Text
                ohos:id="$+id:news_remark"
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:weight="1"
                ohos:text="我是摘要"
                ohos:text_size="14fp"
                ohos:multiple_lines="true"
                ohos:max_text_lines="2"
                ohos:text_color="#888888"/>
            <DependentLayout
                ohos:height="match_parent"
                ohos:width="match_parent"
                ohos:weight="1">
                <Text
                    ohos:id="$+id:news_source"
                    ohos:height="match_content"
                    ohos:width="match_content"
                    ohos:text="来源"
                    ohos:text_size="12fp"
                    ohos:text_color="#CCCCCC"
                    ohos:align_parent_left="true"/>
                <Text
                    ohos:id="$+id:news_time"
                    ohos:height="match_content"
                    ohos:width="match_content"
                    ohos:text="时间"
                    ohos:text_size="12fp"
                    ohos:text_color="#CCCCCC"
                    ohos:right_padding="20vp"
                    ohos:align_parent_right="true"/>
            </DependentLayout>
        </DirectionalLayout>
    </DirectionalLayout>
</DirectionalLayout>

5、创建NewsItemProvider类,并继承BaseItemProvider,重写其中的方法。

@Override
public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
    Component cpt = component;
    if (cpt == null) {
        cpt = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_news_element_layout, null, false);
    }
    News news = list.get(i);
    //封面图
    Image image = (Image) cpt.findComponentById(ResourceTable.Id_news_imgsrc);
    
    //标题
    Text title = (Text) cpt.findComponentById(ResourceTable.Id_news_title);
    title.setText(news.getTitle());
    //摘要
    Text remark = (Text) cpt.findComponentById(ResourceTable.Id_news_remark);
    remark.setText(news.getDigest());
    //来源
    Text source = (Text) cpt.findComponentById(ResourceTable.Id_news_source);
    source.setText(news.getSource());
    //日期
    Text time = (Text) cpt.findComponentById(ResourceTable.Id_news_time);
    time.setText(news.getMtime());
    return cpt;
}

6、在MainAbility中使用OkHttp获取数据并适配ListContainer的数据结构,最后查看运行效果。

/**
 * 复杂数据结构
 */
private void initNewsListContainer() {
    //在子线程中获取数据
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                String response = MainAbilitySlice.this.run("https://api.tianapi.com/bulletin/index?key=您自己的KEY");
                System.out.println(response);
                JSONObject jsonObject = JSONObject.parseObject(response);
                int code = Integer.valueOf(String.valueOf(jsonObject.get("code")));
                String message = String.valueOf(jsonObject.get("msg"));
                String data = String.valueOf(jsonObject.get("newslist"));
                if (code == 200) {
                    List<News> list = JSONArray.parseArray(data, News.class);
                    ListContainer news = (ListContainer) findComponentById(ResourceTable.Id_news_list);
                    NewsItemProvider nip = new NewsItemProvider(list, MainAbilitySlice.this);
                    news.setItemProvider(nip);
                } else {
                    new ToastDialog(getContext())
                        .setText("抛出异常信息: " + message)
                        .setAlignment(LayoutAlignment.CENTER)
                        .show();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
}
2 回复

在HarmonyOS鸿蒙Next中,「3.4 熟知的列表」主要涉及单一列表和组装列表的使用。单一列表是指由相同类型的元素组成的列表,通常用于展示一组相似的数据项。组装列表则是由不同类型的元素组合而成的列表,适用于展示复杂的数据结构或多种类型的内容。

在HAP(HarmonyOS Ability Package)开发中,单一列表可以通过ListContainer组件实现,开发者可以通过数据绑定将数据源与列表项进行关联,实现数据的动态展示。组装列表则可以通过ComponentContainerPageSlider等组件实现,开发者可以根据需求将不同的组件组合在一起,形成复杂的列表结构。

在鸿蒙Next中,列表的渲染和交互性能得到了优化,支持高效的滚动和动态更新。开发者可以通过ListContainerItemProvider接口实现列表项的创建和绑定,通过ComponentContainerComponent接口实现组装列表的布局和交互。

此外,鸿蒙Next还提供了丰富的列表样式和动画效果,开发者可以通过ListContainerItemAnimator接口自定义列表项的动画效果,通过ComponentContainerComponentAnimator接口实现组装列表的动画效果。

总之,在鸿蒙Next中,单一列表和组装列表的使用为开发者提供了灵活的数据展示和交互方式,能够满足不同场景下的需求。

更多关于HarmonyOS 鸿蒙Next中「3.4 熟知的列表」闯荡HAP之单一列表和组装列表的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,「3.4 熟知的列表」部分主要探讨了HAP(HarmonyOS Ability Package)中的单一列表和组装列表。单一列表通常指由单一类型数据项组成的列表,适用于数据项结构简单的场景。组装列表则是由多种类型数据项组合而成的列表,适用于需要展示复杂数据结构的场景。开发者可以根据实际需求选择合适的列表类型,通过合理的数据绑定和布局设计,提升应用的用户体验。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!