鴻蒙ListContainer多布局實(shí)踐

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

1.多布局接口定義

需要實(shí)現(xiàn)多布局需要實(shí)現(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;
    /**
     * 注冊(cè)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("請(qǐng)先注冊(cè)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的條目對(duì)象類

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

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

    private Text tv;

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

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

    /**
     * 返回對(duì)應(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())
                //注冊(cè)之前創(chuàng)建Bean和Holder對(duì)象 !!!必須注冊(cè)不然崩潰
                .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);
    }
運(yùn)行效果
image.png

二.單對(duì)象的多布局實(shí)踐

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

直接上代碼

定義數(shù)據(jù)類型News 實(shí)現(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)建兩個(gè)不同的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) {
        //因?yàn)?個(gè)布局標(biāo)題是同一個(gè)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{
        }
        
        //因?yàn)?個(gè)布局標(biāo)題是同一個(gè)id 所以可以只查找一次
        title = getComponent(ResourceTable.Id_item_news_tv);
        image1 = getComponent(ResourceTable.Id_item_news_image);
        image2 = getComponent(ResourceTable.Id_item_news_image2);
    }
}

兩個(gè)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())
                //注冊(cè)之前創(chuàng)建Bean和Holder對(duì)象 !!!必須注冊(cè)不然崩潰
                .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)容可能也是多種多樣的,在這里我們只需要多注冊(cè)一個(gè)廣告類型并添加相應(yīng)的廣告數(shù)據(jù)即可實(shí)現(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())
                //注冊(cè)之前創(chuàng)建Bean和Holder對(duì)象 !!!必須注冊(cè)不然崩潰
                .register(News.class, NewsHolder.class)
                .register(Ad.class, AdHolder.class)
                //set數(shù)據(jù)
                .setData(newsList)
                .create();
        //給ListContainer設(shè)置provider
        list.setItemProvider(provider);

效果如圖


image.png

接下來是對(duì)于控件事件的處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缀蹄,一起剝皮案震驚了整個(gè)濱河市番甩,隨后出現(xiàn)的幾起案子演顾,更是在濱河造成了極大的恐慌闷旧,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)旨指,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來喳整,“玉大人谆构,你說我怎么就攤上這事】蚨迹” “怎么了搬素?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)魏保。 經(jīng)常有香客問我熬尺,道長(zhǎng),這世上最難降的妖魔是什么谓罗? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任粱哼,我火速辦了婚禮,結(jié)果婚禮上檩咱,老公的妹妹穿的比我還像新娘揭措。我一直安慰自己,他們只是感情好税手,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布蜂筹。 她就那樣靜靜地躺著,像睡著了一般芦倒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上不翩,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天兵扬,我揣著相機(jī)與錄音麻裳,去河邊找鬼。 笑死器钟,一個(gè)胖子當(dāng)著我的面吹牛津坑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播傲霸,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼疆瑰,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了昙啄?” 一聲冷哼從身側(cè)響起穆役,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梳凛,沒想到半個(gè)月后耿币,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡韧拒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年淹接,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叛溢。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡塑悼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出楷掉,到底是詐尸還是另有隱情厢蒜,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布靖诗,位于F島的核電站郭怪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏刊橘。R本人自食惡果不足惜鄙才,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望促绵。 院中可真熱鬧攒庵,春花似錦、人聲如沸败晴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尖坤。三九已至稳懒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慢味,已是汗流浹背场梆。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工墅冷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人或油。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓寞忿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親顶岸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子腔彰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容