本文将专门花一篇来讲述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布局页面
    <ListContainer
        ohos:id="$+id:list_container"
        ohos:height="200vp"
        ohos:width="350vp"
        ohos:layout_alignment="horizontal_center"/>
//第二步创建子布局,这里用两个字段name和address来展示
    <Text
        ohos: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"/>
    <Text
        ohos: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;
    }
    @Override
    public int getCount() {
        return list.size();
    }
    @Override
    public Object getItem(int i) {
        if(list!=null&&list.size()>0){
            return list.get(i);
        }
        return null;
    }
    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public 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
 <PageSlider
        ohos:id="$+id:page_slider"
        ohos:height="300vp"
        ohos:width="300vp"
        ohos:layout_alignment="horizontal_center"/>
    <!--页面导航,前期先不用
    <PageSliderIndicator
        ohos: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"/>
        -->

//第二步创建页面的子布局
    <Text
        ohos: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"/>
    <Image
        ohos:id="$+id:imageComponent"
        ohos:height="200vp"
        ohos:width="match_parent"

        />
    <Text
        ohos: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;
    }
    @Override
    public int getCount() {
        return list.size();
    }
//组装也面内容
    @Override
    public 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;
    }
//注意必须要实现销毁类,不然内容不断添加,并不会移除
    @Override
    public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) {
        componentContainer.removeComponent((Component)o);

    }
    @Override
    public 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() {
            @Override
            public void onPageSliding(int i, float v, int i1) {
                //....
            }

            @Override
            public void onPageSlideStateChanged(int i) {
                 //....
            }

            @Override
            public 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来实现了(即左侧图片下面页面所以提示),留个尾巴吧未来来实现,先继续往下走!

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

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

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐