HarmonyOS开发详解(五)——鸿蒙高级组件数据动态绑定案例实践

本文主要是介绍HarmonyOS开发详解(五)——鸿蒙高级组件数据动态绑定案例实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

         本文将专门花一篇来讲述ListContainer和PageSlider,ListContainer主要是参考官方例子,PageSlider在原有官方例子上进行了一些升级改造。原有例子添加固定的文字,通过改造动态读取本地json内容和本地图片资源。

        Java UI组件中有些需要动态绑定数据的组件,因为系统不了解你的样式(布局)和行为(方法),这就必须要自己按着规则定义,这就导致组件使用为略显复杂,接下来就只讲一下这些稍微复杂的组件。

        1、 ListContainer(列表容器)

       1、ListContainer实现思路分析

         ListContainer列表容器,用来呈现多行连续的同类数据;导致ListContainer稍嫌复杂有两个原因:

        1)列表中每项布局不确定,需要自定义布局(比如新闻每个列表项可能只有标题,也可能有标题、简介、图片,这会导致每行布局不一样)

        2)内容不确定,动态绑定(新闻条数不确定、内容动态加载)

        以上的不确定导致了每个布局需要自己定义,每个数据类型需要自己定义;

        2、ListContainer实现步骤

        1)定义ListContainer:layout下创建ListContainer组件

        2)定义每项布局:layout下创建ListContainer的内容,即子布局,如果是带标题、简介、图片的新闻列表,就定义两个text和一个image。

        3)定义数据实体类:每一条列表的具体组成java类

        4)定义每条列表项的属性:通过实现BaseItemProvider类;因为每项列表内容不确定,通过重写getComponent方法,返回每项布局内容(第二步中的layerout是自定义且空的,这里定义布局和数据的组合方法)

        5)组装ListContainer:通过BaseItemProvider的实现类将数据和ListContainer组合起来;

        6)注册其他行为:比如定义点击事件、定义更新数据;

        完整代码太长,结合上述步骤贴出核心代码,上部分布局类代码,下部分java类代码:

//第一步创建layerout下ListContainer布局页面<ListContainerohos:id="$+id:list_container"ohos:height="200vp"ohos:width="350vp"ohos:layout_alignment="horizontal_center"/>
//第二步创建子布局,这里用两个字段name和address来展示<Textohos:id="$+id:item_index"ohos:height="match_content"ohos:width="match_content"ohos:padding="4vp"ohos:text="Item0"ohos:text_size="20fp"ohos:layout_alignment="center"/><Textohos:id="$+id:item_index1"ohos:height="match_content"ohos:width="match_content"ohos:padding="4vp"ohos:text="Item0"ohos:text_size="20fp"ohos:layout_alignment="left"/>
//第三步,创建ItemBean实体类
public class ItemBean {private String name;private String address;public ItemBean(String name,String address) {this.name = name;this.address=address;}//属性get、set方法省略...
}//第四步,实现BaseItemProvider类,必须实现以下override方法,这样系统就可以根据这些方法对listContainer内容进行组装,并提供一些行为(比如查询长度、返回ID)
public class ItemProvider extends BaseItemProvider {private List<ItemBean> list;private AbilitySlice abilitySlice;public ItemProvider(List<ItemBean> list, AbilitySlice abilitySlice) {this.list = list;this.abilitySlice = abilitySlice;}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int i) {if(list!=null&&list.size()>0){return list.get(i);}return null;}@Overridepublic long getItemId(int i) {return i;}@Overridepublic Component getComponent(int i, Component component, ComponentContainer componentContainer) {Component temp;if(component==null){temp=LayoutScatter.getInstance(abilitySlice).parse(ResourceTable.Layout_list_container_item,null,false);}else{temp=component;}ItemBean itemBean= list.get(i);Text text1=temp.findComponentById(ResourceTable.Id_item_index);text1.setText(itemBean.getName());Text text2 =temp.findComponentById(ResourceTable.Id_item_index1);text2.setText(itemBean.getAddress());return temp;}
}//第五步,在PageSlice里面根据ItemProvider组装ListContainer,构造一个长度20的列表private void initListContainer() {ListContainer listCon=findComponentById(ResourceTable.Id_list_container);List<ItemBean> list=getData();ItemProvider itemProvider=new ItemProvider(list,this);listCon.setItemProvider(itemProvider);}private List<ItemBean> getData(){List<ItemBean> list=new ArrayList<>();for(int i=0;i<20;i++){ItemBean itembean=new ItemBean("item"+i,"address"+i);list.add(itembean);}return list;}
//第六步,定义点击事件listCon.setItemClickedListener((container, component, position, id)->{ItemBean itemBean=(ItemBean)container.getItemProvider().getItem(position);new ToastDialog(this).setText("你点击了"+itemBean.getName()+"__"+itemBean.getAddress()).setAlignment(LayoutAlignment.HORIZONTAL_CENTER).show();});

                以上代码实现效果: 

         2、PageSlider(页面切换组件)

        PageSlider可以通过滚动实现页面间内容切换,每个页面样式内容当然不确定;实现思路和ListContainer一模一样,这里就直接贴出核心代码。

        为了练习,里面添加通过代码创建Text(内容)、image、Text(通过事件获取页码);

   //第一步创建PageSlider<PageSliderohos:id="$+id:page_slider"ohos:height="300vp"ohos:width="300vp"ohos:layout_alignment="horizontal_center"/><!--页面导航,前期先不用<PageSliderIndicatorohos:id="$+id:indicator"ohos:height="match_content"ohos:width="match_content"ohos:padding="8vp"ohos:layout_alignment="horizontal_center"ohos:top_margin="16vp"ohos:background_element="#55FFC0CB"/>-->//第二步创建页面的子布局<Textohos:id="$+id:item_title"ohos:height="match_content"ohos:width="match_content"ohos:layout_alignment="top|center"ohos:padding="4vp"ohos:text="Item0"ohos:text_size="20fp"/><Imageohos:id="$+id:imageComponent"ohos:height="200vp"ohos:width="match_parent"/><Textohos:id="$+id:item_page_num"ohos:height="40vp"ohos:width="80vp"ohos:layout_alignment="bottom|center"ohos:padding="4vp"ohos:text="Item0"ohos:text_size="20fp"/>
//第三步,布局数据内容的实体类
public class ItemPageSlider {private String title;private String imageUrl;private String pageNum;public ItemPageSlider(String title, String imageUrl, String pageNum) {this.title = title;this.imageUrl = imageUrl;this.pageNum = pageNum;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getPageNum() {return pageNum;}public void setPageNum(String pageNum) {this.pageNum = pageNum;}public String getImageUrl() {return imageUrl;}public void setImageUrl(String imageUrl) {this.imageUrl = imageUrl;}
}//第四步,构建数据提供者
public class ItemPageSliderProvider extends PageSliderProvider {private List<ItemPageSlider> list;private Context context;public ItemPageSliderProvider(List<ItemPageSlider> list, Context context) {this.list = list;this.context = context;}@Overridepublic int getCount() {return list.size();}
//组装也面内容@Overridepublic Object createPageInContainer(ComponentContainer componentContainer, int i) {Component component = LayoutScatter.getInstance(this.context).parse(ResourceTable.Layout_page_slider_item, null, false);Text title = component.findComponentById(ResourceTable.Id_item_title);title.setText(list.get(i).getTitle());Text pageNum = component.findComponentById(ResourceTable.Id_item_page_num);pageNum.setText(list.get(i).getPageNum());Image image = component.findComponentById(ResourceTable.Id_imageComponent);image.setPixelMap(CommonUtils.getPixelMapFromPath(context, list.get(i).getImageUrl()));componentContainer.addComponent(component);return component;}
//注意必须要实现销毁类,不然内容不断添加,并不会移除@Overridepublic void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) {componentContainer.removeComponent((Component)o);}@Overridepublic boolean isPageMatchToObject(Component component, Object o) {return false;}
}//第五步,构建数据提供者private void initPageSlider() {PageSlider pageSlider = findComponentById(ResourceTable.Id_page_slider);ItemPageSliderProvider itemPageSliderProvider=new ItemPageSliderProvider(getData(),this);pageSlider.setProvider(itemPageSliderProvider);//监听页面变化pageSlider.addPageChangedListener(new PageSlider.PageChangedListener() {@Overridepublic void onPageSliding(int i, float v, int i1) {//....}@Overridepublic void onPageSlideStateChanged(int i) {//....}@Overridepublic void onPageChosen(int i) {new ToastDialog(getContext()).setText("当前页面索引:"+i++).show();}});//添加页面导航,启用前面的xml布局中PageSliderIndicator,配合此段代码即可实现页面导航 PageSliderIndicator indicator = (PageSliderIndicator)findComponentById(ResourceTable.Id_indicator);ShapeElement normalElement = new ShapeElement();normalElement.setRgbColor(RgbColor.fromArgbInt(0xADD8E6));normalElement.setAlpha(168);normalElement.setShape(ShapeElement.OVAL);normalElement.setBounds(0, 0, 32, 32);ShapeElement selectedElement = new ShapeElement();selectedElement.setRgbColor(RgbColor.fromArgbInt(0x00BFFF));selectedElement.setAlpha(168);selectedElement.setShape(ShapeElement.OVAL);selectedElement.setBounds(0, 0, 48, 48);indicator.setItemElement(normalElement, selectedElement);indicator.setItemOffset(60);indicator.setPageSlider(pageSlider);}

辅助类,用于读取页面内容(用本地文件json定义)、图片 (显示图片资源)

public class CommonUtils {private static final String TAG = "CommonUtils";//读取资源图片public static PixelMap getPixelMapFromPath(Context context, String path) {InputStream inputStream = null;try {inputStream = context.getResourceManager().getRawFileEntry(path).openRawFile();ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();sourceOptions.formatHint = "image/jpg";ImageSource imageSource = ImageSource.create(inputStream, sourceOptions);ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();decodingOptions.desiredSize = new Size(0, 0);decodingOptions.desiredRegion = new Rect(0, 0, 0, 0);decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;return imageSource.createPixelmap(decodingOptions);} catch (IOException e) {LogUtil.error(TAG, e.getMessage());} finally {try {if (inputStream != null) {inputStream.close();}} catch (IOException ex) {LogUtil.error(TAG, ex.getMessage());}}return null;}//读取资源文件json内容public static String getStringFromPath(Context context, String path) {try {Resource dataResource = context.getResourceManager().getRawFileEntry(path).openRawFile();byte[] buffers = new byte[dataResource.available()];if (dataResource.read(buffers) != -1) {return  new String(buffers, StandardCharsets.UTF_8);}} catch (IOException ex) {LogUtil.error(TAG, ex.getMessage());}return Optional.of(path).toString();}}
[{"title": "向日葵","imageUrl": "entry/resources/base/media/xiangrikui.jpg","pageNum": "1"},{"title": "海滩","imageUrl": "entry/resources/base/media/haitan.jpg","pageNum": "2"},{"title": "萧山城市","imageUrl": "entry/resources/base/media/xiaoshan.jpg","pageNum": "3"},{"title": "郁金香","imageUrl": "entry/resources/base/media/yujinxiang.jpg","pageNum": ""},{"title": "鸽子","imageUrl": "entry/resources/base/media/gezi.jpg","pageNum": ""}
]

预期效果:

        本文因为涉及到动态读取图片和内容稍微嫌的复杂,虽然例子并不复杂,因为是改造实话说开发过程中也遇到不少问题,而且本文原计划要实现能够在PageSlider的子页面中动态添加当前页码(如右图的1位置),但是因为实在不知道怎么获取当前页面的内容,最后用ToastDialog来实现了(即左侧图片下面页面所以提示),留个尾巴吧未来来实现,先继续往下走!

        改造例子的时候深深的感受到什么叫“眼高手低”,看代码、抄代码感觉一看都懂,一动手要不不知如何下手,要不就是改错,但别灰心,谁让是新手!

        只要不停下来,未来的路会更顺!

这篇关于HarmonyOS开发详解(五)——鸿蒙高级组件数据动态绑定案例实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131315

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo