2020征文-手机图解鸿蒙列表组件ListContainer

系统
文章由鸿蒙社区产出,想要了解更多内容请前往:51CTO和华为官方战略合作共建的鸿蒙技术社区https://harmonyos.51cto.com/#zz

[[360076]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/#zz

一、什么是ListContainer

ListContainer是用来呈现连续、多行数据的列表组件,包含一系列相同类型的列表项。如下图所示:


二、ListContainer的架构视图

ListContainer的架构视图如下所示:

ListContainer作为列表,其中的列表项数据是由适配器Adapter提供的,适配器Adapter作为ListContainer和数据源之间的中介&桥梁,将数据源中的数据映射到要展示的ListContainer中,ListContainer负责以列表的形式显示适配器Adapter提供的数据。

三、ListContainer的使用步骤

ListContainer的使用步骤主要包括:

1、创建ListContainer

2、创建列表项的布局

3、使用POJO类封装数据源中与每个列表项对应的数据

4、构造数据源

5、构造适配器Adapter

6、将数据源关联到适配器Adapter

7、将适配器Adapter应用到ListContainer

四、ListContainer的使用示例

示例的运行效果如下图所示:

开发步骤如下:

1、创建ListContainer(ability_main.xml)

  1. xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  2.  
  3. ohos:id="$+id:list_container" 
  4.  
  5. ohos:height="match_parent" 
  6.  
  7. ohos:width="match_parent"/> 

 2、创建列表项的布局(item.xml)

  1. xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  2.  
  3. ohos:height="match_content" 
  4.  
  5. ohos:width="match_parent" 
  6.  
  7. ohos:orientation="vertical"
  8.  
  9.  
  10. ohos:id="$+id:name" 
  11.  
  12. ohos:height="50vp" 
  13.  
  14. ohos:width="match_parent" 
  15.  
  16. ohos:padding="5vp" 
  17.  
  18. ohos:auto_font_size="true" 
  19.  
  20. ohos:text_alignment="center"/> 
  21.  
  22.  
  23. ohos:height="1vp" 
  24.  
  25. ohos:width="match_parent" 
  26.  
  27. ohos:background_element="#CCCCCC"/> 

 3、使用POJO类封装数据源中与每个列表项对应的数据(Item.java)

POJO类指的是:只包含属性和相应的getter和setter,而没有业务逻辑的类。

  1. public class Item { 
  2.  
  3. private String name
  4.  
  5. public Item(String name) { 
  6.  
  7. this.name = name
  8.  
  9.  
  10. public String getName() { 
  11.  
  12. return name
  13.  
  14.  
  15. public void setName(String name) { 
  16.  
  17. this.name = name
  18.  
  19.  

 4、构造数据源(MainAbilitySlice.java) 

  1. public class MainAbilitySlice extends AbilitySlice { 
  2.  
  3. @Override 
  4.  
  5. public void onStart(Intent intent) { 
  6.  
  7. super.onStart(intent); 
  8.  
  9. super.setUIContent(ResourceTable.Layout_ability_main); 
  10.  
  11. List list = getData(); 
  12.  
  13.  
  14. private List getData() { 
  15.  
  16. List list = new ArrayList<>(); 
  17.  
  18. for (int i = 1; i <= 100; i++) { 
  19.  
  20. list.add(new Item("Item " + i)); 
  21.  
  22.  
  23. return list; 
  24.  
  25.  

 5、构造适配器Adapter(MyItemProvider.java)

常用的适配器类是RecycleItemProvider,继承该类时需要重写四个方法:getCount()、getItem()、getItemId()和getComponent()。其中,对于方法getComponent(),当某个列表项从不可见变为可见时会自动调用该方法,在该方法中适配器Adapter会从数据源取数据,并将返回的数据封装在一个Component对象中,以便将该对象返回给ListContainer,从而将数据映射到对应的列表项。

  1. public class MyItemProvider extends RecycleItemProvider { 
  2.  
  3. private List list; 
  4.  
  5. private AbilitySlice slice; 
  6.  
  7. public MyItemProvider(List list, AbilitySlice slice) { 
  8.  
  9. this.list = list; 
  10.  
  11. this.slice = slice; 
  12.  
  13.  
  14. @Override 
  15.  
  16. public int getCount() { 
  17.  
  18. return list.size(); 
  19.  
  20.  
  21. @Override 
  22.  
  23. public Object getItem(int position) { 
  24.  
  25. return list.get(position); 
  26.  
  27.  
  28. @Override 
  29.  
  30. public long getItemId(int position) { 
  31.  
  32. return position; 
  33.  
  34.  
  35. @Override 
  36.  
  37. public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) { 
  38.  
  39. convertComponent = LayoutScatter.getInstance(slice) 
  40.  
  41. .parse(ResourceTable.Layout_item, nullfalse); 
  42.  
  43. Text text = (Text) convertComponent.findComponentById(ResourceTable.Id_name); 
  44.  
  45. text.setText(list.get(position).getName()); 
  46.  
  47. return convertComponent; 
  48.  
  49.  

 6、将数据源关联到适配器Adapter(MainAbilitySlice.java) 

  1. public class MainAbilitySlice extends AbilitySlice { 
  2.  
  3. @Override 
  4.  
  5. public void onStart(Intent intent) { 
  6.  
  7. ...... 
  8.  
  9. List list = getData(); 
  10.  
  11. MyItemProvider myItemProvider = new MyItemProvider(list, this); 
  12.  
  13.  
  14. ...... 
  15.  

 7、将适配器Adapter应用到ListContainer(MainAbilitySlice.java) 

  1. public class MainAbilitySlice extends AbilitySlice { 
  2.  
  3. @Override 
  4.  
  5. public void onStart(Intent intent) { 
  6.  
  7. ...... 
  8.  
  9. MyItemProvider myItemProvider = new MyItemProvider(list, this); 
  10.  
  11. ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_list_container); 
  12.  
  13. listContainer.setItemProvider(myItemProvider); 
  14.  
  15.  
  16. ...... 
  17.  

 五、适配器Adapter的优化

对于上面的第5步,当某个列表项从不可见变为可见时,对于自动调用的方法getComponent(),我们是根据列表项的布局文件item.xml创建了一个列表项的实例。这样的做法性能较差。因为系统会对变为不可见的列表项实例进行缓存,所以对于方法getComponent()中的第二个参数convertComponent有可能不为null。当convertComponent不为null时,说明系统把缓存中的某个列表项实例传递过来了,因此,完全可以复用该列表项实例,而没有必要重新创建一个列表项实例。优化方式如下:

  1. public class MyItemProvider extends RecycleItemProvider { 
  2.  
  3. ...... 
  4.  
  5. @Override 
  6.  
  7. public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) { 
  8.  
  9. if (convertComponent == null) { 
  10.  
  11. convertComponent = LayoutScatter.getInstance(slice) 
  12.  
  13. .parse(ResourceTable.Layout_item, nullfalse); 
  14.  
  15.  
  16. Text text = (Text) convertComponent.findComponentById(ResourceTable.Id_name); 
  17.  
  18. text.setText(list.get(position).getName()); 
  19.  
  20. return convertComponent; 
  21.  
  22.  

 六、使用ViewHolder对适配器Adapter做终极优化

在上面的代码中,得到列表项实例后(不管是新创建的列表项实例,还是从缓存中获得的列表项实例),都要调用方法findComponentById()以获得列表项中的子组件。调用方法findComponentById()是比较耗费性能的,所以好的做法是:在新创建列表项实例时,就调用方法findComponentById()以获得列表项中的所有子组件,并且将所有子组件通过ViewHolder绑定到列表项实例。这样,当从缓存中获得列表项实例后,就无需再调用方法findComponentById()了,直接获得列表项实例绑定的ViewHolder就可以得到所有子组件了。优化方式如下:

  1. public class MyItemProvider extends RecycleItemProvider { 
  2.  
  3. ...... 
  4.  
  5. @Override 
  6.  
  7. public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) { 
  8.  
  9. ViewHolder viewHolder; 
  10.  
  11. if (convertComponent == null) { 
  12.  
  13. convertComponent = LayoutScatter.getInstance(slice) 
  14.  
  15. .parse(ResourceTable.Layout_item, nullfalse); 
  16.  
  17. viewHolder = new ViewHolder(); 
  18.  
  19. viewHolder.text = (Text) convertComponent.findComponentById(ResourceTable.Id_name); 
  20.  
  21. convertComponent.setTag(viewHolder); 
  22.  
  23. else { 
  24.  
  25. viewHolder = (ViewHolder) convertComponent.getTag(); 
  26.  
  27.  
  28. viewHolder.text.setText(list.get(position).getName()); 
  29.  
  30. return convertComponent; 
  31.  
  32.  
  33. class ViewHolder { 
  34.  
  35. Text text; 
  36.  
  37.  

 如果你理解了为什么要这么优化,相信你会发现:当列表项中只有一个子组件时,也可以不引入ViewHolder,而是将这个子组件直接绑定到列表项实例。代码如下所示:

  1. public class MyItemProvider extends RecycleItemProvider { 
  2.  
  3. ...... 
  4.  
  5. @Override 
  6.  
  7. public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) { 
  8.  
  9. Text text; 
  10.  
  11. if (convertComponent == null) { 
  12.  
  13. convertComponent = LayoutScatter.getInstance(slice) 
  14.  
  15. .parse(ResourceTable.Layout_item, nullfalse); 
  16.  
  17. text = (Text) convertComponent.findComponentById(ResourceTable.Id_name); 
  18.  
  19. convertComponent.setTag(text); 
  20.  
  21. else { 
  22.  
  23. text = (Text) convertComponent.getTag(); 
  24.  
  25.  
  26. text.setText(list.get(position).getName()); 
  27.  
  28. return convertComponent; 
  29.  
  30.  

 示例源代码,请见附件。

欢迎订阅我的专栏【图解鸿蒙】:

https://harmonyos.51cto.com/column/27

©著作权归作者和HarmonyOS技术社区共同所有,如需转载,请注明出处,否则将追究法律责任

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/#zz

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2021-08-12 14:59:15

鸿蒙HarmonyOS应用

2020-12-22 11:09:20

鸿蒙Feature AbiAbilitySlic

2020-12-28 11:19:06

鸿蒙HarmonyOSPage Abilit

2020-12-04 12:42:59

组件鸿蒙Text

2020-12-22 09:48:18

鸿蒙HarmonyOS应用程序

2020-12-23 11:36:23

鸿蒙HarmonyOS应用程序开发

2020-12-22 11:20:36

鸿蒙HarmonyOS游戏

2020-12-23 11:24:34

鸿蒙开发IDE安装

2020-12-23 11:45:27

鸿蒙HarmonyOSTextField组件

2020-12-28 11:30:07

鸿蒙HarmonyOS分布式

2020-12-25 10:39:53

鸿蒙开发JS

2021-08-25 09:49:48

鸿蒙HarmonyOS应用

2020-12-24 10:05:54

鸿蒙鸿蒙开发Hello World

2020-12-24 11:24:31

鸿蒙开发JS

2020-12-09 11:53:24

鸿蒙开发HelloWord

2020-12-15 11:57:49

Hi3861 HarmonyOS开发板

2020-12-18 11:05:25

鸿蒙HarmonyOS游戏

2020-12-29 09:59:01

鸿蒙HarmonyOS智能家居

2022-04-24 15:17:56

鸿蒙操作系统

2020-12-14 09:58:28

鸿蒙HarmonyOS手表游戏
点赞
收藏

51CTO技术栈公众号