RecycleView + SwipeRefreshLayout 对adapter和刷新的封装

用了recycleview一段时间了,感觉效果很不错,但是就是adapter的写法太过于复杂,并且配合谷歌官方的SwipeRefreshLayout使用很是复杂。今天就对其进行一次封装。

1.首先recycleview是强制需要viewholder模式的,所以我们对其viewholder的封装是必须的;

/**
 * Created by zhenfei.wang on 2016/7/12.
 * recycleview的通用ViewHolder
 */
public class RcyViewHolder extends RecyclerView.ViewHolder{
    private SparseArray mViews;
    private View mConvertView;
    private Context mContext;

    public RcyViewHolder(Context context, View itemView, ViewGroup parent)
    {
        super(itemView);
        mContext = context;
        mConvertView = itemView;
        mViews = new SparseArray();
    }


    public static RcyViewHolder get(Context context, ViewGroup parent, int layoutId)
    {
        View itemView = LayoutInflater.from(context).inflate(layoutId, parent,
                false);
        RcyViewHolder holder = new RcyViewHolder(context, itemView, parent);
        return holder;
    }


    /**
     * 通过viewId获取控件
     *
     * @param viewId
     * @return
     */
    public <T extends View> T getView(int viewId)
    {
        View view = mViews.get(viewId);
        if (view == null)
        {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }

2.其次是封装通用的CommontAdapter;

/**
 * Created by zhenfei.wang on 2016/7/12.
 * recycleview 通用的Adapter
 * 只支持单一布局
 */
public abstract class RcyCommonAdapter <T> extends RecyclerView.Adapter{
    protected Context mContext;
    protected int mLayoutId;
    protected List<T> mDatas;
    protected LayoutInflater mInflater;
    protected boolean loadMore;


    /**
     *
     * @param context
     * @param layoutId
     * @param datas
     * @param loadMore 是否需要底部加载更多
     * @param rv
     */
    public RcyCommonAdapter(Context context, int layoutId, List<T> datas , boolean loadMore,RecyclerView rv)
    {
        mContext = context;
        mInflater = LayoutInflater.from(context);
        mLayoutId = layoutId;
        mDatas = datas;
        this.loadMore = loadMore;
        setSpanCount(rv);
    }

    /**
     * 设置每个条目占用的列数
     * @param recyclerView recycleView
     */
    private void setSpanCount(RecyclerView recyclerView) {
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    int type = getItemViewType(position);
                    // 若是最后一个 且需要加载更多,则强制让最后一个条目占满横屏
                    if (type == R.layout.item_list_footer) {
                        return gridLayoutManager.getSpanCount();
                    } else {
                        return 1;
                    }
                }
            });
        }
    }


    @Override
    public RcyViewHolder onCreateViewHolder(final ViewGroup parent, int viewType)
    {
        return RcyViewHolder.get(mContext, parent, viewType);
    }

    @Override
    public int getItemViewType(int position) {
        int lId = 0;
        if(loadMore && position + 1 == getItemCount()){
            lId = R.layout.item_list_footer;
        } else {
            lId = getmLayoutId(position);
        }
        return lId;
    }

    @Override
    public void onBindViewHolder(RcyViewHolder holder, int position)
    {
        if(getItemViewType(position)  == R.layout.item_list_footer){
            checkLoadStatus(holder);
        }else {
            convert(holder, mDatas.get(position));
        }
    }

    private void checkLoadStatus(RcyViewHolder holder) {
        if(getItemCount() != 1){
             holder.getView(R.id.tv_item_footer_load_more).setVisibility(View.GONE);
             holder.getView(R.id.pb_item_footer_loading).setVisibility(View.VISIBLE);
        }else {
            holder.getView(R.id.tv_item_footer_load_more).setVisibility(View.GONE);
            holder.getView(R.id.pb_item_footer_loading).setVisibility(View.GONE);
        }
    }


    public abstract void convert(RcyViewHolder holder, T t);
    public abstract int getmLayoutId(int position);

    @Override
    public int getItemCount()
    {
        return  loadMore ? mDatas.size() + 1 : mDatas.size();
    }
}
3.使用方法,我们写个简单的TestAdapter,可见只要复写两个方法,第一就是为不同的位置数据适配不同的布局资源,第二个就是数据适配

/**
 * Created by zhenfei.wang on 2016/7/12.
 */
public class TestAdapter extends RcyCommonAdapter {
    public TestAdapter(Context context, int layoutId, List datas , boolean loadMore, RecyclerView rv) {
        super(context, layoutId, datas, loadMore, rv);
    }
    @Override
    public int getmLayoutId(int position) {
        return position % 2 == 0 ? R.layout.item1 : R.layout.item2;
    }

    @Override
    public void convert(RcyViewHolder holder, String s) {
        TextView tv = holder.getView(R.id.tv);
        tv.setText(s);
    }

}
4.提供一下我们的主Activity和其布局;

public class MainActivity extends Activity implements SwipeRefreshLayout.OnRefreshListener{
    private RecyclerView rv;
    private SwipeRefreshLayout refreshLayout;
    private LinearLayoutManager layoutManager;
    private List data;
    private TestAdapter adapter;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    Utils.refresh(data);
                    adapter.notifyDataSetChanged();
                    refreshLayout.setRefreshing(false);
                    break;
                case 1:
                    Utils.loadMore(data);
                    adapter.notifyDataSetChanged();
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        rv = (RecyclerView) findViewById(R.id.rv);
        refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh_layout);
        init();
    }

    private void init() {
        data = new ArrayList();
        layoutManager = new LinearLayoutManager(this);
//        layoutManager = new GridLayoutManager(this, 2);
        refreshLayout.setOnRefreshListener(this);
        rv.setLayoutManager(layoutManager);
        adapter = new TestAdapter(this, R.layout.item1, data, true, rv);
        rv.addOnScrollListener(new OnRecyclerScrollListener(adapter, refreshLayout, layoutManager) {
	    // 加载更多数据
            @Override
            public void loadMore() {
                handler.sendEmptyMessageDelayed(1, 2000);
            }
        });
        rv.setAdapter(adapter);
        refreshLayout.setRefreshing(true);
        onRefresh();
    }

    // 数据刷新
    @Override
    public void onRefresh() {
        handler.sendEmptyMessageDelayed(0, 2000);
    }

xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

            android:id="@+id/refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

                    android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#93BBBB" />
    

5.可以看到我们把RecyclerView.OnScrollListener封装成自己的,我们只需要上拉加载更多的事件传出来即可,其他的不想看到,可以用一个抽象方法搞定;

/**
 * Created by zhenfei.wang on 2016/7/12.
 * recycle的滑动监听,上拉加载更多操作
 */
public abstract class OnRecyclerScrollListener extends RecyclerView.OnScrollListener{
    private int lastVisibleItem = 0;
    private RecyclerView.Adapter mAdapter;
    private SwipeRefreshLayout refreshLayout;
    private LinearLayoutManager layoutManager;

    public OnRecyclerScrollListener(RecyclerView.Adapter mAdapter, SwipeRefreshLayout refreshLayout, LinearLayoutManager layoutManager) {
        this.mAdapter = mAdapter;
        this.refreshLayout = refreshLayout;
        this.layoutManager = layoutManager;
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        //如果滚动到底部,就获取更多的数据
        if (mAdapter != null && newState == RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 == mAdapter.getItemCount()) {
            if (!refreshLayout.isRefreshing()) {
                loadMore();
            }
        }
    }
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        lastVisibleItem = layoutManager.findLastVisibleItemPosition();
    }

    public abstract void loadMore();
}

想要项目的可以去我的github下载:https://github.com/179576267/RecycleView-swipeRefreshLayout/tree/1.0

你可能感兴趣的:(技术要点)