RecycleView简单的万能适配器

RecyclerView的万能适配器

相信每次用到RecyclerView大多人都会写一次适配器,发现十分的麻烦,所以我就去找了几篇文章,发现一个简单的万能适配器,是要写一次适配器就够了,而且还添加了点击跟长按事件,代码比较简单易懂,所以分享给大家。文章出处:http://www.cnblogs.com/liushilin/p/5720926.html

界面效果


RecyclerView万能适配器的简单构造思路:
多半还是和构造ListView的万能适配器差不多,毕竟RecyclerView就是为了替代它们出现的,只是RecyclerView封装了ViewHolder而已,而我们要实现把ViewHolder和Adaper封装成一个万能的适配器,我们肯定还是得像上篇提到的利用每个view独一无二的id进行键值映射来做处理,当然我们还是用现在官方推荐的SparseArray,这个东西在能替代HashMap的时候真的好用,性能的优化就不用多说了。

代码

先看看核心代码:

我们封装了ViewHolder,为了把设置值等都封装进去,我们对外提供了set方法。通过一个getView来实现之前类似于ViewHolder的设置标签的效果。如果已经绑定,则直接返回,否则放到SparseArray中。

下面是ViewHolder的基本封装。如果你有之前ListView的ViewHolder的封装,这个看起来我相信很好理解。

package com.example.nanchen.commonadaperrecyclerdemo;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;

/**
 * 万能的RecyclerView的ViewHolder
 * Created by 南尘 on 16-7-30.
 */
public class BaseRecyclerHolder extends RecyclerView.ViewHolder {

    private SparseArray<View> views;
    private Context context;

    private BaseRecyclerHolder(Context context,View itemView) {
        super(itemView);
        this.context = context;
        //指定一个初始为8
        views = new SparseArray<>(8);
    }

    /**
     * 取得一个RecyclerHolder对象
     * @param context 上下文
     * @param itemView 子项
     * @return 返回一个RecyclerHolder对象
     */
    public static BaseRecyclerHolder getRecyclerHolder(Context context,View itemView){
        return new BaseRecyclerHolder(context,itemView);
    }

    public SparseArray<View> getViews(){
        return this.views;
    }

    /**
     * 通过view的id获取对应的控件,如果没有则加入views中
     * @param viewId 控件的id
     * @return 返回一个控件
     */
    @SuppressWarnings("unchecked")
    public <T extends View> T getView(int viewId){
        View view = views.get(viewId);
        if (view == null ){
            view = itemView.findViewById(viewId);
            views.put(viewId,view);
        }
        return (T) view;
    }

    /**
     * 设置字符串
     */
    public BaseRecyclerHolder setText(int viewId,String text){
        TextView tv = getView(viewId);
        tv.setText(text);
        return this;
    }

    /**
     * 设置图片
     */
    public BaseRecyclerHolder setImageResource(int viewId,int drawableId){
        ImageView iv = getView(viewId);
        iv.setImageResource(drawableId);
        return this;
    }

    /**
     * 设置图片
     */
    public BaseRecyclerHolder setImageBitmap(int viewId, Bitmap bitmap){
        ImageView iv = getView(viewId);
        iv.setImageBitmap(bitmap);
        return this;
    }

    /**
     * 设置图片
     */
    public BaseRecyclerHolder setImageByUrl(int viewId,String url){
        Picasso.with(context).load(url).into((ImageView) getView(viewId));
        //        ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context));
        //        ImageLoader.getInstance().displayImage(url, (ImageView) getView(viewId));
        return this;
    }
}

然后是Recycler的Adapter,由于RecyclerView的Adapter必须继承自RecyclerView.Adapter,并且指定我们写的ViewHolder为泛型,为了达到万能的效果,我们把需要传入的Java Bean属性直接用一个泛型T指代。

下面这些值得你注意:

1)RecyclerView没有提供Item的点击事件,所以我们需要自己自定义,建议实现在Adapter中,因为adapter里面会用到ViewHolder,这样有助用我们写每一项的点击事件。

2)RecyclerView不仅支持全局刷新,而且支持局部刷新,所以我们建议把添加和删除的方法直接写在Adapter中。

3)我们为了达到万能的效果,所以我们把设置holder的方法作为一个抽象方法,方面我们通过viewId传值到相应的控件中,把整个Adapter变成一个抽象方法,这样在子类中就可以去通过强制实现的方式把我们的数据填充进去。

还是直接看源码吧。

package com.example.nanchen.commonadaperrecyclerdemo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

/**
 * 万能的RecyclerView适配器
 * Created by 南尘 on 16-7-30.
 */
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<BaseRecyclerHolder> {

    private Context context;//上下文
    private List<T> list;//数据源
    private LayoutInflater inflater;//布局器
    private int itemLayoutId;//布局id
    private boolean isScrolling;//是否在滚动
    private OnItemClickListener listener;//点击事件监听器
    private OnItemLongClickListener longClickListener;//长按监听器
    private RecyclerView recyclerView;

    //在RecyclerView提供数据的时候调用
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        this.recyclerView = recyclerView;
    }

    @Override
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);
        this.recyclerView = null;
    }

    /**
     * 定义一个点击事件接口回调
     */
    public interface OnItemClickListener {
        void onItemClick(RecyclerView parent, View view, int position);
    }

    public interface OnItemLongClickListener {
        boolean onItemLongClick(RecyclerView parent, View view, int position);
    }

    /**
     * 插入一项
     *
     * @param item
     * @param position
     */
    public void insert(T item, int position) {
        list.add(position, item);
        notifyItemInserted(position);
    }

    /**
     * 删除一项
     *
     * @param position 删除位置
     */
    public void delete(int position) {
        list.remove(position);
        notifyItemRemoved(position);
    }

    public BaseRecyclerAdapter(Context context, List<T> list, int itemLayoutId) {
        this.context = context;
        this.list = list;
        this.itemLayoutId = itemLayoutId;
        inflater = LayoutInflater.from(context);

        //        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        //            @Override
        //            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        //                super.onScrollStateChanged(recyclerView, newState);
        //                isScrolling = !(newState == RecyclerView.SCROLL_STATE_IDLE);
        //                if (!isScrolling) {
        //                    notifyDataSetChanged();
        //                }
        //            }
        //        });
    }

    @Override
    public BaseRecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(itemLayoutId, parent, false);
        return BaseRecyclerHolder.getRecyclerHolder(context, view);
    }

    @Override
    public void onBindViewHolder(final BaseRecyclerHolder holder, int position) {

        if (listener != null){
            holder.itemView.setBackgroundResource(R.drawable.recycler_bg);//设置背景
        }
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (listener != null && view != null && recyclerView != null) {
                    int position = recyclerView.getChildAdapterPosition(view);
                    listener.onItemClick(recyclerView, view, position);
                }
            }
        });


        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                if (longClickListener != null && view != null && recyclerView != null) {
                    int position = recyclerView.getChildAdapterPosition(view);
                    longClickListener.onItemLongClick(recyclerView, view, position);
                    return true;
                }
                return false;
            }
        });

        convert(holder, list.get(position), position, isScrolling);

    }

    @Override
    public int getItemCount() {
        return list == null ? 0 : list.size();
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }

    public void setOnItemLongClickListener(OnItemLongClickListener longClickListener) {
        this.longClickListener = longClickListener;
    }

    /**
     * 填充RecyclerView适配器的方法,子类需要重写
     *
     * @param holder      ViewHolder
     * @param item        子项
     * @param position    位置
     * @param isScrolling 是否在滑动
     */
    public abstract void convert(BaseRecyclerHolder holder, T item, int position, boolean isScrolling);
}

实体类get、set方法Data.java:

public class Data {

    private String text;
    private String text2;
    private int imageId;
    private String imageUrl;

    public Data(String text) {
        this.text=text;
    }
    public Data(String text, String text2, int imageId) {
        this.text = text;
        this.text2=text2;
        this.imageId = imageId;
    }

    public Data(String text, String text2, String imageUrl) {
        this.imageUrl = imageUrl;
        this.text = text;
        this.text2=text2;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getText2() {
        return text2;
    }

    public void setText2(String text2) {
        this.text2 = text2;
    }

    public int getImageId() {
        return imageId;
    }

    public void setImageId(int imageId) {
        this.imageId = imageId;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }
}

在主页面中调用:

package com.example.nanchen.commonadaperrecyclerdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {

    private List<Data> list;
    private RecyclerView recyclerView;
    private BaseRecyclerAdapter<Data> adapter;
    private EditText text;

    @SuppressWarnings("unchecked")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        list = new ArrayList<>();

        initList();

        adapter = new BaseRecyclerAdapter<Data>(this,list,R.layout.list_item) {
            @Override
            public void convert(BaseRecyclerHolder holder, Data item, int position, boolean isScrolling) {
                holder.setText(R.id.item_text,item.getText());
                if (item.getImageUrl() != null){
                    holder.setImageByUrl(R.id.item_image,item.getImageUrl());
                }else {
                    holder.setImageResource(R.id.item_image,item.getImageId());
                }
            }

        };

        adapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(RecyclerView parent, final View view, int position) {
                Toast.makeText(MainActivity.this, String.format(Locale.CHINA,"你点击了第%d项,长按会删除!",position),Toast.LENGTH_SHORT).show();
            }
        });

        adapter.setOnItemLongClickListener(new BaseRecyclerAdapter.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(RecyclerView parent, View view, int position) {
                adapter.delete(position);
                return true;
            }
        });

        text = (EditText) findViewById(R.id.main_text);
        recyclerView = (RecyclerView) findViewById(R.id.main_recycler);
        recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
        recyclerView.setAdapter(adapter);



    }

    public void initList(){
        for (int i = 0; i < 5; i++) {
            list.add(new Data("本地 "+i,R.mipmap.ic_launcher));
        }
        for (int i = 0; i < 5; i++) {
            list.add(new Data("网络 "+i,"http://pic.cnblogs.com/face/845964/20160301162812.png"));
        }
    }

    public void btnClick(View view) {
        String string = text.getText().toString().trim();
        Data data = new Data(string,R.mipmap.ic_launcher);
//        list.add(list.size()/2,data);
        adapter.insert(data,list.size()/2);

        Toast.makeText(MainActivity.this,list.size()+"",Toast.LENGTH_SHORT).show();
    }
}

这样就基本完成了,像不同的layout布局,只要再建一个layout布局,替换适配器初始化中的布局,然后通过holder.getView(R.id.textView)就可以获取到控件id,就可以设置,或者holder.setText(R.id.item_text, item.getText());方法也是一样的,效果如下:
在这里插入图片描述
在这里插入图片描述

源码地址

github提取:https://github.com/nanchen2251/CommonAdapterRecyclerDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值