万能Adapter

原生的RecyclerView.Adapter使用起来有些麻烦,所以大多数情况我们使用的是三方的adapter,比如大神hongyang的,或者BaseQuickAdapter.之前本来同事写了一个,领导说用三方的,结果现在又要用自己的.......上意难测.....所以自己写一个吧.该adapter实现了单布局,多布局,树形层级的功能

核心代码

public abstract class BaseAdapter<T> extends RecyclerView.Adapter<BaseViewHoder> {

    protected List<T> mData = new ArrayList<>();
    private int mLayoutId;
    protected LayoutInflater mInflater;

    public BaseAdapter(List<T> data, int layoutId) {
        if (data != null) {
            this.mData.addAll(data);
        }
        this.mLayoutId = layoutId;
    }

    @NonNull
    @Override
    public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        mInflater = LayoutInflater.from(viewGroup.getContext());
        View view = mInflater.inflate(mLayoutId, viewGroup, false);
        return new BaseViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull BaseViewHolder viewHoder, final int position) {
        if (itemOnclickListener != null) {
            viewHoder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    itemOnclickListener.onItemClick(position);
                }
            });
        }
        if (itemOnLongclickListener != null) {
            viewHoder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    return itemOnLongclickListener.onItemLongClick(position);
                }
            });
        }
        convert(viewHoder, mData.get(position));
    }

    /**
     * 用户实现
     * @param viewHoder
     * @param item
     */
    public abstract void convert(BaseViewHolder viewHoder, T item);

    @Override
    public int getItemCount() {
        return mData.size();
    }

    private ItemOnclickListener itemOnclickListener;

    public void setItemOnclickListener(final ItemOnclickListener itemOnclickListener) {
        this.itemOnclickListener = itemOnclickListener;

    }

    public void setNewData(List<T> data) {
        this.mData.clear();
        this.mData.addAll(data);
        notifyDataSetChanged();
    }

    public T getItem(int pos) {
        return mData.get(pos);
    }

    public void setEmptyView(int empId) {
        if (mData.isEmpty()){
            mLayoutId = empId;
        }
    }

    public interface ItemOnclickListener {
        void onItemClick(int position);
    }

    private ItemOnLongclickListener itemOnLongclickListener;

    public void setItemOnLongclickListener(final ItemOnLongclickListener itemOnLongclickListener) {
        this.itemOnLongclickListener = itemOnLongclickListener;

    }

    public interface ItemOnLongclickListener {
        boolean onItemLongClick(int position);
    }
}

我们加载布局资源的时候通常使用如下三个方法

View view = View.inflate(this, R.layout.activity_handler, null);
        //第一个方法调用第二个方法
        view = LayoutInflater.from(this).inflate(R.layout.activity_handler,null);
        //第二个方法调用第三个方法,我们从这看源码
        view = LayoutInflater.from(this).inflate(R.layout.activity_handler,null,false);

在RecyclerView.Adapter中我们如果使用前两个方法,会发现item布局并没有铺满RecyclerView, 这是什么原因?请参考LayoutInflater中inflate方法三个参数的区别

public class BaseViewHoder extends RecyclerView.ViewHolder {
   private SparseArray<View> views = new SparseArray<>();


    public BaseViewHolder(@NonNull View itemView) {
        super(itemView);
    }

    public <T extends View> T getView(int viewId){
        View view = views.get(viewId);
        if (view == null){
            view = itemView.findViewById(viewId);
        }
        return (T) view;
    }
    /**
     * 设置文字
     * @param viewId
     * @param text
     * @return
     */
    public BaseViewHolder setText(int viewId, String text){
        TextView view = getView(viewId);
        view.setText(text);
        return this;
    }

    /**
     * 设置
     * @param viewId
     * @param check
     * @return
     */
    public BaseViewHolder setChecked(int viewId, boolean check){
        CheckBox view = getView(viewId);
        view.setChecked(check);
        return this;
    }

    /**
     * 设置gone 和 VISIBLE
     * @param viewId
     * @param gone
     * @return
     */
    public BaseViewHolder setGone(int viewId, boolean gone){
        View view = getView(viewId);
        view.setVisibility(gone?View.GONE:View.VISIBLE);
        return this;
    }
    /**
     * 设置INVISIBLE 和 VISIBLE
     * @param viewId
     * @param visible
     * @return
     */
    public BaseViewHolder setVisibility(int viewId, boolean visible){
        View view = getView(viewId);
        view.setVisibility(visible?View.VISIBLE:View.INVISIBLE);
        return this;
    }

    /**
     * 加载网络图片的时候,用户可以选择的三方框架很多,这里交给用户自己去选择
     * @param viewId
     * @param imageLoader
     * @return
     */
    public BaseViewHolder setImageUrl(int viewId, ImageLoader imageLoader){
        ImageView view = getView(viewId);
        if (imageLoader != null){
            imageLoader.load(view,imageLoader.mUrl);
        }
        return this;
    }


    public static abstract class ImageLoader{

        private String mUrl;

        public ImageLoader(String mUrl) {
            this.mUrl = mUrl;
        }

        abstract void load(ImageView imageView, String url);
    }
}

使用

  RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        BaseAdapter<Data> baseAdapter = new BaseAdapter<Data>(list, R.layout.item_adpter) {
            @Override
            public void convert(BaseViewHoder viewHoder, final Data item) {
                viewHoder.setText(R.id.tv, item.name)
                        .setImageUrl(R.id.iv, new BaseViewHoder.ImageLoader(item.url) {
                            @Override
                            void load(ImageView imageView, String url) {
                                Glide.with(AdpterActivity.this).load(url).into(imageView);
                            }
                        });
            }

        };
        baseAdapter.setItemOnclickListener(new BaseAdapter.ItemOnclickListener() {
            @Override
            public void onItemClick(int position) {
                Toast.makeText(AdpterActivity.this, list.get(position).name, Toast.LENGTH_SHORT).show();
            }
        });
        baseAdapter.setItemOnLongclickListener(new BaseAdapter.ItemOnLongclickListener() {
            @Override
            public boolean onItemLongClick(int position) {
                Toast.makeText(AdpterActivity.this, "66666666666", Toast.LENGTH_SHORT).show();
                return true;
            }
        });
        recyclerView.setAdapter(baseAdapter);

多类型Item的BaseMultiItemAdapter

public abstract class BaseMultiItemAdapter<T extends MultiItemEntity> extends BaseAdapter<T> {

    public BaseMultiItemAdapter(List<T> data) {
        super(data, -1);
    }

    @Override
    public int getItemViewType(int position) {
        T t = mData.get(position);
        return t.getLayoutId();
    }
    /**
     * 通过源码可知:
     * @param viewGroup
     * @param viewType 是getItemViewType()方法的返回值,在这里将布局id返回
     * @return
     */
   public BaseViewHoder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        mInflater = LayoutInflater.from(viewGroup.getContext());
        View view = null;
        try {
             view = mInflater.inflate(viewType, viewGroup, false);
        }catch (Exception e){
            //如果用户没设置layoutId,抛出异常提示用户
            throw new RuntimeException("please setLayoutId in MultiItemEntity");
        }

        return new BaseViewHoder(view);
    }

}

public interface MultiItemEntity {
    /**
     * 设置布局id
     * @return
     */
    int getLayoutId();
}

使用

 public class Data implements MultiItemEntity{
        String name;
        String url;

        @Override
        public int getLayoutId() {
            return R.layout.item_adpter;
        }
    }

 BaseMultiItemAdapter baseAdapter = new BaseMultiItemAdapter<Data>(list) {
            @Override
            public void convert(BaseViewHoder viewHoder, Data item) {
                switch (item.getLayoutId()){
                    case R.layout.item_adpter:
                        if (Integer.parseInt(item.name)%2==0) {
                            viewHoder.setText(R.id.tv, item.name);
                        }else {
                            viewHoder.setText(R.id.tv, "77777777777");
                        }
                        break;
                }
            }
        };

树形多层级recycleview

public abstract class BaseTreeItemAdapter<T extends AbsTreeEntity> extends BaseMultiItemAdapter<T> {

    /**
     * 用来存放展开的数据
     */
    private List<T> visibles = new ArrayList<>();

    public BaseTreeItemAdapter(List<T> data) {
        super(data);
        getVisiblaData();
    }

    @Override
    public int getItemViewType(int position) {
        T t = visibles.get(position);
        return t.getLayoutId();
    }

    @Override
    public int getItemCount() {
        return visibles.size();
    }

    private void getVisiblaData() {
        if (mData==null)return;
        for (T data : mData) {
            //如果是根节点,直接加入
            if (data.getParent() == null){
                visibles.add(data);
                continue;
            }
            //如果不是根节点,判断其父节点是否展开,展开则加入visibles集合,
            // 否则将其设置为未展开,解决合起时孙子布局的现实问题
            if (data.getParent().isExpand()) {
                visibles.add(data);
            }else {
                data.setExpand(false);
            }
        }

    }

    private ItemOnclickListener itemOnclickListener;

    public void setItemOnclickListener(final ItemOnclickListener itemOnclickListener) {
        this.itemOnclickListener = itemOnclickListener;

    }

    public interface ItemOnclickListener {
        void onItemClick(int position);
    }

    private ItemOnLongclickListener itemOnLongclickListener;

    public void setItemOnLongclickListener(final ItemOnLongclickListener itemOnLongclickListener) {
        this.itemOnLongclickListener = itemOnLongclickListener;

    }

    public interface ItemOnLongclickListener {
        boolean onItemLongClick(int position);
    }

    @Override
    public void onBindViewHolder(@NonNull BaseViewHoder viewHoder, final int position) {
        if (itemOnclickListener != null) {
            viewHoder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    T t = visibles.get(position);
                    if (t != null) {
                        t.setExpand(!t.isExpand());
                    }
                    visibles.clear();
                    getVisiblaData();
                    notifyDataSetChanged();
                    itemOnclickListener.onItemClick(position);
                }
            });
        }
        if (itemOnLongclickListener != null) {
            viewHoder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    return itemOnLongclickListener.onItemLongClick(position);
                }
            });
        }
        convert(viewHoder, visibles.get(position));

    }
}

其中

public abstract class AbsTreeEntity implements MultiItemEntity {

    /**
     * 是否展开
     */
    private boolean isExpand;
    /**
     * 父节点
     */
    private AbsTreeEntity parent;

    public AbsTreeEntity getParent() {
        return parent;
    }

    public void setParent(AbsTreeEntity parent) {
        this.parent = parent;
    }


    public void setExpand(boolean expand) {
        isExpand = expand;
    }

    public boolean isExpand() {
        return isExpand;
    }

}

使用

 private List<AbsTreeEntity> getData(){
        List<AbsTreeEntity> list = new ArrayList<>();
        Title father = new Title("王健林","父亲");
        father.setExpand(true);
        list.add(father);
        for (int i = 0; i < 3; i++) {
            Content son = new Content("王思聪","儿子");
            son.setParent(father);
            son.setExpand(true);
            list.add(son);
            Content sun = new Content("小马","孙子");
            sun.setParent(son);
            list.add(sun);
        }
        return list;
    }


    class Title  extends AbsTreeEntity{
        String name;
        String url;

        public Title(String name, String url) {
            this.name = name;
            this.url = url;
        }

        public String getName() {
            return name;
        }

        public Title setName(String name) {
            this.name = name;
            return this;
        }

        public String getUrl() {
            return url;
        }

        public Title setUrl(String url) {
            this.url = url;
            return this;
        }

        @Override
        public int getLayoutId() {
            return R.layout.item_title;
        }
        
    }

    class Content extends AbsTreeEntity{
        String name;
        String url;
        
        public Content(String name, String url) {
            this.name = name;
            this.url = url;
        }

        public String getName() {
            return name;
        }

        public Content setName(String name) {
            this.name = name;
            return this;
        }

        public String getUrl() {
            return url;
        }

        public Content setUrl(String url) {
            this.url = url;
            return this;
        }

        @Override
        public int getLayoutId() {
            return R.layout.item_content;
        }
        
    }


 RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        BaseTreeItemAdapter baseAdapter = new BaseTreeItemAdapter<AbsTreeEntity>(getData()) {
            @Override
            public void convert(BaseViewHoder viewHoder, AbsTreeEntity item) {
                switch (item.getLayoutId()) {
                    case R.layout.item_title:
                        Title title = (Title) item;
                        viewHoder.setText(R.id.tv, title.getName() +"         "+title.getUrl());

                        break;
                    case R.layout.item_content:
                        Content content = (Content) item;
                        viewHoder.setText(R.id.tv, content.getName() +"         "+content.getUrl());

                        break;

                }
            }
        };
        baseAdapter.setItemOnclickListener(new BaseTreeItemAdapter.ItemOnclickListener() {
            @Override
            public void onItemClick(int position) {
                Toast.makeText(TreeActivity.this, "7777777777", Toast.LENGTH_SHORT).show();
            }
        });
        baseAdapter.setItemOnLongclickListener(new BaseTreeItemAdapter.ItemOnLongclickListener() {
            @Override
            public boolean onItemLongClick(int position) {
                Toast.makeText(TreeActivity.this, "66666666666", Toast.LENGTH_SHORT).show();
                return true;
            }
        });
        recyclerView.setAdapter(baseAdapter);

这里需要注意的是,层级与层级之间的缩合是通过用户在布局中设置的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352