HarmonyOS开发,从listContainer谈容器类控件的使用

开发 前端 OpenHarmony
容器类控件在生活中还是比较常见的,比如文件列表,图片轮播等等,容器类控件主要就是负责容纳真正的内容,在界面上一般没有自己真正的"形象",属于内容后面的绿叶,在后面默默的撑起控件的光彩。

[[441284]]

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

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

https://harmonyos.51cto.com

1.什么叫容器类控件

容器类控件在生活中还是比较常见的,比如文件列表,图片轮播等等。

2.容器类控件有什么特点

容器类控件主要就是负责容纳真正的内容,在界面上一般没有自己真正的"形象",属于内容后面的绿叶,在后面默默的撑起控件的光彩。

以listContainer的示意图:

#星光计划2.0#HarmonyOS开发,从listContainer谈容器类控件的使用-鸿蒙HarmonyOS技术社区

假设我们有一个下载列表,要做这样一个列表,有两种方法,一种就是硬编码,把东西一个一个写在layout上面,但那显然是最低级最无脑的做法,咱们程序员都自诩高智商人才,不能做那蠢事是不。

另一种高级的做法就是搞一个列表容器,把要显示的内容抽象成一个小的layout,然后按顺序排列出来塞到listContainer就行.

3.怎么学

3.1 准备好你的layout内容

首先是官方的教程:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-component-listcontainer-0000001060007847

这篇教程很基础,介绍了一个最基本的列表容器,但是也仅限基础,如果是app开发新手比如我这样的就很容易搞蒙,一眼看去不知所以,所以我觉得还是按我的方式去解释这个东西。

4.准备工作

首先设计好你要展示的内容,比如下载列表,我们设计成左边放一张图片,右边分两个控件,一个Text,下方放一个进度条,大概就这意思:

#星光计划2.0#HarmonyOS开发,从listContainer谈容器类控件的使用-鸿蒙HarmonyOS技术社区 

先把这个layout设计出来:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <DirectionalLayout 
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  4.     ohos:height="match_parent" 
  5.     ohos:width="match_parent" 
  6.     ohos:orientation="horizontal"
  7.  
  8.     <Image 
  9.         ohos:id="$+id:movie_img" 
  10.         ohos:height="100vp" 
  11.         ohos:width="100vp" 
  12.         ohos:layout_alignment="left" 
  13.         ohos:image_src="$media:setting" 
  14.         ohos:scale_mode="clip_center" 
  15.         /> 
  16.     <DirectionalLayout 
  17.         ohos:id="$+id:movie_info" 
  18.         ohos:height="match_parent" 
  19.         ohos:width="match_parent" 
  20.         ohos:orientation="vertical" 
  21.         > 
  22.         <Text 
  23.             ohos:id="$+id:movie_name" 
  24.             ohos:width="match_parent" 
  25.             ohos:height="30vp" 
  26.             ohos:left_margin="3vp" 
  27.             ohos:text_size="30fp" 
  28.             ohos:text="亮剑-18" 
  29.             /> 
  30.         <ProgressBar 
  31.             ohos:id="$+id:progressbar" 
  32.             ohos:progress_width="10vp" 
  33.             ohos:height="60vp" 
  34.             ohos:width="600vp" 
  35.             ohos:max="100" 
  36.             ohos:min="0" 
  37.             ohos:progress="60"/> 
  38.     </DirectionalLayout> 
  39.  
  40. </DirectionalLayout> 

预览窗口看见到是这样:

#星光计划2.0#HarmonyOS开发,从listContainer谈容器类控件的使用-鸿蒙HarmonyOS技术社区

3.2 准备listContainer

有了layout,还要有容器把他装起来,就跟果树长果子一样,有了果子,还得有树。

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <DirectionalLayout 
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  4.     ohos:height="match_parent" 
  5.     ohos:width="match_parent" 
  6.     ohos:orientation="vertical"
  7.     <Text 
  8.         ohos:width="match_parent" 
  9.         ohos:height="30vp" 
  10.         ohos:text="下载列表" 
  11.         ohos:text_size="30vp" 
  12.         ohos:top_margin="10vp" 
  13.         ohos:text_alignment="center" 
  14.         /> 
  15.     <ListContainer 
  16.         ohos:id="$+id:download_list" 
  17.         ohos:height="match_content" 
  18.         ohos:width="match_parent" 
  19.         ohos:scrollbar_background_color="#d2a456" 
  20.         > 
  21.  
  22.     </ListContainer> 
  23.  
  24. </DirectionalLayout> 

但是这东西没有界面,目前还没法预览,实在要预览的话是这个界面。

#星光计划2.0#HarmonyOS开发,从listContainer谈容器类控件的使用-鸿蒙HarmonyOS技术社区

4.初始化

在下载列表的abilitySlice的onStart里面假如初始化函数:

  1. @Override 
  2.  protected void onStart(Intent intent) { 
  3.      super.onStart(intent); 
  4.      setUIContent(ResourceTable.Layout_movie_containerlist); 
  5.  
  6.      initDownloadListContainer(); 
  7.  } 
  8.  
  9.  private void initDownloadContainerList(){ 
  10.      ListContainer listContainer=(ListContainer) findComponentById(ResourceTable.Id_download_list); 
  11.      if(listContainer != null){ 
  12.          ArrayList<downloadItem> list=getData(); 
  13.          downloadItemProvider itemPro=new downloadItemProvider(list,this); 
  14.          listContainer.setItemProvider(itemPro); 
  15.      } 
  16.  } 

 看第10行,首先咱们把listContainer获取到,为什么要获取到呢,因为接下来我们就要往里塞东西了。

那怎么塞呢,看第15行,我们往这个listContainer里面设置了一叫itemPro的东西,这里引入了一个Provider,这个provider负责帮我们提供数据,对于这个provider官方的文档有简单的几个接口介绍:

#星光计划2.0#HarmonyOS开发,从listContainer谈容器类控件的使用-鸿蒙HarmonyOS技术社区

其他的都还好懂,感觉最后一个有些费解,什么意思呢:

你那个listContainer嘛,里面肯定是有很多项,像一个数组一样,我们想拿到每一个列表项里面的图形控件,就得用这个接口,不然大家都长一样,你怎么知道你的数据结构对应哪个图形控件。

这里我们看到itemPro的创建需要一个list做参数,那在java里面就用ArrayList了,我们就来实现一下这个获取列表的接口:

  1. private ArrayList<downloadItem> getData(){ 
  2.       ArrayList<downloadItem> list=new ArrayList<>(); 
  3.  
  4.       for (int i=0;i<8;i++) 
  5.       { 
  6.           downloadItem item = new downloadItem("亮剑-"+i+1); 
  7.           DirectionalLayout layout = (DirectionalLayout) LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_movie_item,null,false); 
  8.           item.setLayout(layout); 
  9.           item.setProgress(i*10); 
  10.           list.add(item); 
  11.  
  12.       } 
  13.  
  14.       return list; 
  15.   } 

 这个很好理解了,就是创建一个list,然后把数据填充进去,这里的示例,我让每一个列表显示不一样的文字,然后再把每个进度条显示不一样的值,返回过去就行了。

这里面又涉及到一个东西,就是我们的downloadItem,这个item其实就是对应的我们那个下载信息展示的具体信息,就是java里面的一个类,先创造出一个结构类出来:

  1. public class downloadItem { 
  2.  
  3.     private static final String TAG = imageScannerSlice.class.getSimpleName(); 
  4.  
  5.     private static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00201, TAG); 
  6.  
  7.  
  8.     String name
  9.     Image image; 
  10.     int progress;//[0-100]% 
  11.  
  12.     DirectionalLayout layout; 
  13.  
  14.     public downloadItem(String name){ 
  15.         this.name = name
  16.  
  17.     } 
  18.  
  19.     public void downloadItem(String name, Image img) { 
  20.         this.name = name
  21.         this.image = image; 
  22.     } 
  23.  
  24.     public void setLayout(DirectionalLayout layout){ 
  25.         if(layout == null){ 
  26.             HiLog.error(LABEL_LOG,"setLayout is NULL"); 
  27.             return
  28.         } 
  29.         this.layout =layout; 
  30.  
  31.         Text text =(Text) layout.findComponentById(ResourceTable.Id_movie_name); 
  32.         text.setText(name); 
  33.     } 
  34.  
  35.     public void setProgress(int progress) { 
  36.         if(progress<0) progress=0; 
  37.         if (progress>100) progress=100; 
  38.  
  39.         this.progress = progress; 
  40.         if(layout == null){ 
  41.             return
  42.         } 
  43.         ProgressBar progressBar =(ProgressBar) layout.findComponentById(ResourceTable.Id_progressbar); 
  44.         progressBar.setProgressValue(progress); 
  45.     } 

可以看到,我们在这个结构里面做了一个setLayout的动作,这个就是为了把我们每个结构对应的图形控件对应起来,有了这东西,在Provider里面的getComponent接口里面就好填充数据了,整个provider长这样:

  1. public class downloadItemProvider extends BaseItemProvider { 
  2.  
  3.     private List<downloadItem> list; 
  4.     private AbilitySlice slice; 
  5.  
  6.     public downloadItemProvider(List<downloadItem> list, AbilitySlice slice){ 
  7.         this.list = list; 
  8.         this.slice = slice; 
  9.  
  10.     } 
  11.  
  12.     @Override 
  13.     public int getCount() { 
  14.         return this.list!=null ? this.list.size() : 0; 
  15.     } 
  16.  
  17.     @Override 
  18.     public Object getItem(int i) { 
  19.         if(this.list != null && i>0 && i <list.size()) 
  20.         { 
  21.             return this.list.get(i); 
  22.         } 
  23.         return null
  24.     } 
  25.  
  26.     @Override 
  27.     public long getItemId(int i) { 
  28.  
  29.         return i; 
  30.     } 
  31.  
  32.  
  33.     @Override 
  34.     public Component getComponent(int i, Component component, ComponentContainer componentContainer) { 
  35.  
  36.          if(component != null){ 
  37.             return component; 
  38.         } 
  39.          
  40.         downloadItem item = (downloadItem)this.getItem(i); 
  41.         return item.layout; 
  42.  
  43.     } 
  44.  
  45.  

可以看到我们的getComponent就是把我们的downloadItem找到,然后直接返回我们事先用setlayout接口传进去的layout控件。

5.效果展示

把上面的代码片段进行整合,放进工程里面,最后的效果就是这样:

#星光计划2.0#HarmonyOS开发,从listContainer谈容器类控件的使用-鸿蒙HarmonyOS技术社区

到这里,我们的listContainer,列表容器控件就完成了,如果感觉没看懂的,可以先去看一下官方的教程:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-component-listcontainer-0000001060007847

然后再来看本教程,应该就能理清了。

6.pageSlider控件

所谓的pageSlider能够实现一个大图轮播的效果,官方文档在这:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-component-pageslider-0000001091933258

效果在官方手册上也有

从编程逻辑上来说,跟listContainer的逻辑是一样的,首先准备好你的展示页面,然后创建一个容器:pageSlide,再给pageSlider一个Provider用来提供数据,再初始化一下就好了。

如果读懂了上面listContainer的逻辑,这个pagesiler简直就太小儿科了,基于这样的逻辑,我们能很快把我们的下载列表改造成pagesilde形式:

相关的xml文件我就不贴了,参照官方代码就可以做到

  1. public class downloadItemPageProvider extends PageSliderProvider { 
  2.     //数据实体类 
  3. //    public static class DataItem{ 
  4. //        String mText; 
  5. //        public DataItem(String txt) { 
  6. //            mText = txt; 
  7. //        } 
  8. //    } 
  9.     // 数据源,每个页面对应list中的一项 
  10.     private List<downloadItem> list; 
  11.     private Context mContext; 
  12.  
  13.     public downloadItemPageProvider(List<downloadItem> list, Context context) { 
  14.         this.list = list; 
  15.         this.mContext = context; 
  16.     } 
  17.     @Override 
  18.     public int getCount() { 
  19.         return list.size(); 
  20.     } 
  21.     @Override 
  22.     public Object createPageInContainer(ComponentContainer componentContainer, int i) { 
  23.  
  24.         final downloadItem item = list.get(i); 
  25. //        DirectionalLayout layout =new DirectionalLayout(mContext);//(DirectionalLayout) componentContainer.findComponentById(ResourceTable.Id_home_info); 
  26.  
  27.  
  28.         DirectionalLayout layout =(DirectionalLayout) LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_home_info,null,false); 
  29.  
  30.         componentContainer.addComponent(layout); 
  31.         item.setLayout(layout); 
  32.         return layout; 
  33.     } 
  34.     @Override 
  35.     public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) { 
  36.         componentContainer.removeComponent((Component) o); 
  37.     } 
  38.     @Override 
  39.     public boolean isPageMatchToObject(Component component, Object o) { 
  40.         //可添加具体处理逻辑 
  41.         //... 
  42.         return true
  43.     } 

这个pageSlid的Provider跟List的Provider大体逻辑差不多的,只是稍稍有些不同,就是这个里面需要实现createPageInContainer,而不是list的Provider里面的getComponent接口,但是仔细观察我里面的代码,跟之前那个如出一辙,然后改造一下初始化那里:

  1. private void initPageSlide(String account) { 
  2.       pageSlider = (PageSlider) findComponentById(ResourceTable.Id_page_slider); 
  3.       pageSlider.setProvider(new downloadItemPageProvider(getData(), this)); 
  4.   } 

 这样就能轻松的做出一个左右滑屏的页面滑动器。

#星光计划2.0#HarmonyOS开发,从listContainer谈容器类控件的使用-鸿蒙HarmonyOS技术社区

7.总结

个人感觉比较自豪的一处是那个数据结构跟图形控件绑定的逻辑,比官方的好用。

其实总结下来,做容器类的空间需要的流程是:

#星光计划2.0#HarmonyOS开发,从listContainer谈容器类控件的使用-鸿蒙HarmonyOS技术社区

理解了这个套路.你就能做出想要的效果

其实还可以把pageSilde和listContainer结合起来使用做出更复杂好玩的界面效果,期待你的反馈。

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

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

https://harmonyos.51cto.com

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

2021-08-12 14:59:15

鸿蒙HarmonyOS应用

2011-04-19 17:06:24

bada控件bada

2009-08-05 18:32:28

HtmlTextWriASP.NET控件开发

2021-08-25 09:49:48

鸿蒙HarmonyOS应用

2020-12-28 10:15:18

鸿蒙HarmonyOSListContain

2011-12-06 10:04:12

QQ手机移动应用应用设计

2010-08-06 14:13:31

FlexDataGrid分页控

2011-12-05 23:08:11

诺基亚

2015-08-18 14:10:09

Docker云计算PaaS

2009-11-04 13:33:13

ADO.NET Dat

2014-06-08 23:19:43

DevOps敏捷开发

2017-08-17 16:12:09

MySQL架构设计

2019-12-24 11:19:44

容器DockerLinux

2017-11-21 14:32:05

容器持久存储

2021-08-22 17:22:31

VS Code容器开发人员

2009-09-11 11:33:58

C# WinForm控Attribute

2015-07-02 10:37:32

C#Json字符串类代码

2013-08-26 17:41:43

JavaScriptWindows 8.1

2012-12-27 16:46:19

Android开发AutoComplet

2010-05-04 13:20:01

负载均衡服务
点赞
收藏

51CTO技术栈公众号