鴻蒙ListContainer多布局實踐

鴻蒙的ListContainer多布局實現(xiàn),不需要編寫Provider,只需要編寫條目對應(yīng)的Holder即可,省下不少代碼

1.多布局接口定義

需要實現(xiàn)多布局需要實現(xiàn)該接口
public interface Mult {
    //返回多布局類型
    int mult();
}

2.BaseProvider

public class BaseProvider<T> extends BaseItemProvider {

    private List<T> data;
    private Context context;
    protected boolean enableMult = false;
    protected ArrayList<Class<ViewHolder<T>>> holders;
    protected HashMap<Class<T>,Class<ViewHolder<T>>> map;
    protected int multCount = 1;
    /**
     * 注冊holder
     * @param holder
     */
    public BaseProvider<T> register(Class<T> pojo,Class<ViewHolder<T>> holder){
        if(holders == null){
            holders = new ArrayList<>();
            map = new HashMap<>();
        }
        holders.add(holder);
        map.put(pojo,holder);
        return this;
    }

    /**
     * 是否允許多布局
     * @param enableMult
     * @return
     */
    public BaseProvider<T> mult(boolean enableMult){
        this.enableMult = enableMult;
        return this;
    }

    public BaseProvider(Context context) {
        super();
        this.context = context;
        data = new ArrayList<>();
    }

    public BaseProvider(Context context,List<T> data) {
        super();
        this.data = data;
        this.context = context;
    }

    public void refreshData(List<T> data){
        setData(data);
        notifyDataChanged();
    }

    public void setData(List<T> data){
        this.data = data;
    }

    public void more(List<T> more){
        this.data.addAll(more);
        notifyDataChanged();
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public T getItem(int i) {
        return data.get(i);
    }

    public void setMultCount(int count) {
        this.multCount = count;
    }

    @Override
    public long getItemId(int pos) {
        return pos;
    }

    @Override
    public int getItemComponentType(int position) {
        T data = getItem(position);

        if(data instanceof Mult){
            Mult mult = (Mult)data;
            Class holderClass = map.get(data.getClass());
            return holderClass.hashCode()+mult.mult();
        }

        return position;
    }

    @Override
    public int getComponentTypeCount() {
        return multCount;
    }

    @Override
    public Component getComponent(int pos, Component component, ComponentContainer componentContainer) {
        T itemData = data.get(pos);

        //單布局
        Class<ViewHolder<T>> holderClass = map.get(itemData.getClass());
        if(holderClass == null){
            throw new RuntimeException("請先注冊holder和數(shù)據(jù)類型");
        }
        T data = itemData;
        ViewHolder<T> holder = ViewHolder.<T>get(context,component,data,pos,holderClass);
        return holder.getRootComponent();
    }


}

3.ViewHolder

public abstract class ViewHolder<Data> {

    protected HashMap<Integer, Component> mComponents;
    protected Component mRootComponent;
    protected Context context;
    protected int layoutId;
    protected int position;
    protected LayoutScatter layoutScatter;
    public ViewHolder(Context context) {
        super();
        this.context = context;
        if(layoutScatter == null){
            layoutScatter = LayoutScatter.getInstance(context);
        }

        mComponents = new HashMap<>();
    }

    public void setLayout(Data data){
        layoutId = getLayoutId(data,position);
        this.mRootComponent = layoutScatter.parse(layoutId,null,false);
        mRootComponent.setTag(this);
        findComponent(data,position);
    }

    public static <T> ViewHolder<T> get(Context context,Component convertView,T data,int pos,Class holderClass)  {
        ViewHolder holder = null;
        try {
            if(convertView == null){
                Constructor<ViewHolder<T>> declaredConstructor = holderClass.getDeclaredConstructor(Context.class);
                holder = declaredConstructor.newInstance(context);
                holder.position = pos;
                holder.setLayout(data);
            }else{
                holder = (ViewHolder)convertView.getTag();
                holder.position = pos;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        holder.convert(data,pos);
        return holder;
    }

    public Component getRootComponent(){
        return mRootComponent;
    }

    public abstract void convert(Data data,int position);

    /**
     * 通過componentId獲取控件
     *
     * @param viewId
     * @return
     */
    public <T extends Component> T getComponent(int viewId) {
        Component view = mComponents.get(viewId);
        if (view == null) {
            view = mRootComponent.findComponentById(viewId);
            mComponents.put(viewId, view);
        }
        return (T) view;
    }

    protected abstract int getLayoutId(Data data,int position);

    protected abstract void findComponent(Data data,int position);
}

4. 還有我們輔助生成provider的工具類

public class ProviderCreator {

    public static class Builder<T>{
        private BaseProvider<T> provider;

        public Builder(Context context) {
            super();
            provider = new BaseProvider<>(context);
        }

        public Builder<T> register(Class pojo, Class holder){
            provider.register(pojo,holder);
            return this;
        }

        public Builder<T> setData(List<T> data){
            provider.setData(data);
            return this;
        }

        public Builder<T> multCount(int count){
            provider.setMultCount(count);
            return this;
        }

        public BaseProvider<T> create(){
            return provider;
        }
    }
}

接下里就可以愉快的使用啦

一.首先是單布局的使用,就是最常見的用法

List的條目對象類

public class Normal {
    public Normal(String text) {
        this.text = text;
    }

    public String text;
}
條目對應(yīng)的holder !!! 一個類必須對應(yīng)一個holder
public class NormalHolder extends ViewHolder<Normal> {

    private Text tv;

    public NormalHolder(Context context) {
        super(context);
    }

    /**
     * 具體的實現(xiàn)
     * @param normal
     * @param position
     */
    @Override
    public void convert(Normal normal, int position) {
        tv.setText(normal.text);
    }

    /**
     * 返回對應(yīng)的布局
     * @param normal
     * @param position
     * @return
     */
    @Override
    protected int getLayoutId(Normal normal, int position) {
        return ResourceTable.Layout_item_normal;
    }

    /**
     * 查找控件 
     * @param normal
     * @param position
     */
    @Override
    protected void findComponent(Normal normal, int position) {
        tv = getComponent(ResourceTable.Id_item_normal_tv1);
    }
}

在Slice中使用

 /**
     * 最基礎(chǔ)用法 單布局
     * @param list
     */
    public void normal(ListContainer list){
        BaseProvider<Normal> provider = new ProviderCreator.Builder<Normal>(getAbility())
                //注冊之前創(chuàng)建Bean和Holder對象 !!!必須注冊不然崩潰
                .register(Normal.class, NormalHolder.class)
                //set數(shù)據(jù)
                .setData(MapUtil.<Normal>list().adds(
                    new Normal("1"),
                    new Normal("2"),
                    new Normal("3"),
                    new Normal("4"),
                    new Normal("5")
                )).create();

        //給ListContainer設(shè)置provider
        list.setItemProvider(provider);
    }
運行效果
image.png

二.單對象的多布局實踐

我們會遇到相同的數(shù)據(jù)類型,但是顯示的內(nèi)容不一致的情況

直接上代碼

定義數(shù)據(jù)類型News 實現(xiàn)Mult接口
public class News implements Mult {
    
    public News(int style, Text title, List<String> images) {
        this.style = style;
        this.title = title;
        this.images = images;
    }

    private int style; //顯示類型
    private Text title; //標(biāo)題
    private List<String> images; //圖片列表

    @Override
    public int mult() {
        return style;
    }
}

定義NewsHolder,并創(chuàng)建兩個不同的xml布局
public class NewsHolder extends ViewHolder<News> {

    private Text title;
    private Image image1;
    private Image image2;

    public NewsHolder(Context context) {
        super(context);
    }

    @Override
    public void convert(News news, int position) {
        //因為2個布局標(biāo)題是同一個id 所以可以直接設(shè)置 無需判斷
        title.setText(news.title);

        if(news.mult() == 1){
            Glide.with(context)
                    .load(news.images.get(0))
                    .diskCacheStrategy(DiskCacheStrategy.NONE)
                    .skipMemoryCache(true)
                    .into(image1);
        }else{
            Glide.with(context)
                    .load(news.images.get(0))
                    .diskCacheStrategy(DiskCacheStrategy.NONE)
                    .skipMemoryCache(true)
                    .into(image1);
            Glide.with(context)
                    .load(news.images.get(1))
                    .diskCacheStrategy(DiskCacheStrategy.NONE)
                    .skipMemoryCache(true)
                    .into(image2);
        }

    }

    @Override
    protected int getLayoutId(News news, int position) {
        //根據(jù)mult返回不同的布局
        if(news.mult() == 1){
            //右邊有圖
            return ResourceTable.Layout_item_news1;
        }else{
            //下面有圖
            return ResourceTable.Layout_item_news2;
        }
    }

    @Override
    protected void findComponent(News news, int position) {
        //類似
        if(news.mult() == 1){
        }else{
        }
        
        //因為2個布局標(biāo)題是同一個id 所以可以只查找一次
        title = getComponent(ResourceTable.Id_item_news_tv);
        image1 = getComponent(ResourceTable.Id_item_news_image);
        image2 = getComponent(ResourceTable.Id_item_news_image2);
    }
}

兩個xml布局如下

item_news1.xml
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="horizontal">
    <Text
        ohos:id="$+id:item_news_tv"
        ohos:background_element="#ffffff"
        ohos:height="100vp"
        ohos:text_size="20vp"
        ohos:text_color="#000000"
        ohos:width="match_content"/>
    <Image
        ohos:id="$+id:item_news_image"
        ohos:height="100vp"
        ohos:width="100vp"/>
</DirectionalLayout>
item_news2.xml
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="vertical">
    <Text
        ohos:id="$+id:item_news_tv"
        ohos:background_element="#ffffff"
        ohos:height="100vp"
        ohos:text_size="20vp"
        ohos:text_color="#000000"
        ohos:width="match_parent"/>
  <DirectionalLayout
      ohos:orientation="horizontal"
      ohos:height="match_content"
      ohos:width="match_parent">
      <Image
          ohos:id="$+id:item_news_image"
          ohos:height="100vp"
          ohos:width="100vp"/>
      <Image
          ohos:id="$+id:item_news_image2"
          ohos:height="100vp"
          ohos:width="100vp"/>
  </DirectionalLayout>
</DirectionalLayout>

最后一步 在slice中使用~

###
  List<String> style1List = new ArrayList<>();
        style1List.add("https://img03.sogoucdn.com/app/a/100520093/8379901cc65ba509-45c21ceb904429fc-e8e0ced72c7814e527ca276e0fe48673.jpg");
        List<String> style2List = new ArrayList<>();
        style2List.add("https://img03.sogoucdn.com/app/a/100520093/ae588be27ee085c4-fd668f66a830d70e-60b57587f934a25debc8247d3769d0ce.jpg");
        style2List.add("https://img03.sogoucdn.com/app/a/100520093/ae588be27ee085c4-fd668f66a830d70e-bcb76412aab683a7d1f972c04a769065.jpg");

        List<News> newsList =  MapUtil.<News>list().adds(
                new News(1,"第一條重大新聞",style1List),
                new News(2,"第二條重大新聞",style2List),
                new News(1,"第三條重大新聞",style1List),
                new News(1,"第四條重大新聞",style1List),
                new News(1,"第五條重大新聞",style1List),
                new News(2,"第六條重大新聞",style2List),
                new News(1,"第一條重大新聞",style1List),
                new News(2,"第二條重大新聞",style2List),
                new News(1,"第三條重大新聞",style1List),
                new News(1,"第四條重大新聞",style1List),
                new News(1,"第五條重大新聞",style1List),
                new News(2,"第六條重大新聞",style2List),
                new News(1,"第一條重大新聞",style1List),
                new News(2,"第二條重大新聞",style2List),
                new News(1,"第三條重大新聞",style1List),
                new News(1,"第四條重大新聞",style1List),
                new News(1,"第五條重大新聞",style1List),
                new News(2,"第六條重大新聞",style2List)
        );
        BaseProvider<News> provider = new ProviderCreator.Builder<News>(getAbility())
                //注冊之前創(chuàng)建Bean和Holder對象 !!!必須注冊不然崩潰
                .register(News.class, NewsHolder.class)
                //set數(shù)據(jù)
                .setData(newsList)
                .create();
        //給ListContainer設(shè)置provider
        list.setItemProvider(provider);

顯示效果如下


image.png

3.多類型多布局的使用

如上面新聞列表中有廣告的插入 而廣告的數(shù)據(jù)類型一定不是News,而且廣告的顯示內(nèi)容可能也是多種多樣的,在這里我們只需要多注冊一個廣告類型并添加相應(yīng)的廣告數(shù)據(jù)即可實現(xiàn),無需任何別的代碼

直接上代碼,在剛才的基礎(chǔ)上新增加廣告類和廣告holder

廣告類


public class Ad implements Mult {
    public Ad(String adContent, int adStyle) {
        this.adContent = adContent;
        this.adStyle = adStyle;
    }

    public String adContent;//廣告內(nèi)容
    public int adStyle; //顯示類型

    //如果沒有其他返回類型,返回0即可
    @Override
    public int mult() {
        return adStyle;
    }
}

廣告holder

public class AdHolder extends ViewHolder<Ad> {

    private Text title;

    public AdHolder(Context context) {
        super(context);
    }

    @Override
    public void convert(Ad ad, int position) {
        title.setText(ad.adContent);
    }

    @Override
    protected int getLayoutId(Ad ad, int position) {
        if(ad.mult() == 1){
            return ResourceTable.Layout_item_ad1;

        }else{
            return ResourceTable.Layout_item_ad2;
        }

    }

    @Override
    protected void findComponent(Ad ad, int position) {
        title = getComponent(ResourceTable.Id_item_ad_tv);
    }
}

item_ad1.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="horizontal">
    <Text
        ohos:id="$+id:item_ad_tv"
        ohos:background_element="#ffffff"
        ohos:height="100vp"
        ohos:text_size="20vp"
        ohos:text_color="#ff00ff"
        ohos:width="match_content"/>

</DirectionalLayout>

item_ad2.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="horizontal">
    <Text
        ohos:id="$+id:item_ad_tv"
        ohos:background_element="#ffffff"
        ohos:height="100vp"
        ohos:text_size="50vp"
        ohos:text_color="#ff00ff"
        ohos:width="match_content"/>

</DirectionalLayout>

slice中使用

        List<String> style1List = new ArrayList<>();
        style1List.add("https://img03.sogoucdn.com/app/a/100520093/8379901cc65ba509-45c21ceb904429fc-e8e0ced72c7814e527ca276e0fe48673.jpg");
        List<String> style2List = new ArrayList<>();
        style2List.add("https://img03.sogoucdn.com/app/a/100520093/ae588be27ee085c4-fd668f66a830d70e-60b57587f934a25debc8247d3769d0ce.jpg");
        style2List.add("https://img03.sogoucdn.com/app/a/100520093/ae588be27ee085c4-fd668f66a830d70e-bcb76412aab683a7d1f972c04a769065.jpg");

        List<Mult> newsList =  MapUtil.<Mult>list().adds(
                new News(1,"第一條重大新聞",style1List),
                new News(2,"第二條重大新聞",style2List),
                new Ad("廣告1",1),
                new Ad("廣告2",2),
                new News(1,"第三條重大新聞",style1List),
                new News(1,"第四條重大新聞",style1List),
                new News(1,"第五條重大新聞",style1List),
                new News(2,"第六條重大新聞",style2List)
        );

        BaseProvider<Mult> provider = new ProviderCreator.Builder<Mult>(getAbility())
                //注冊之前創(chuàng)建Bean和Holder對象 !!!必須注冊不然崩潰
                .register(News.class, NewsHolder.class)
                .register(Ad.class, AdHolder.class)
                //set數(shù)據(jù)
                .setData(newsList)
                .create();
        //給ListContainer設(shè)置provider
        list.setItemProvider(provider);

效果如圖


image.png

接下來是對于控件事件的處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容