本文主要是介绍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开发详解(五)——鸿蒙高级组件数据动态绑定案例实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!