Android之RecycleView下拉刷新上滑加载更多

    xiaoxiao2021-03-25  117

    本文注意记录一些零碎的东西

    闲来无事,自定义了一个下拉刷新上滑加载更多的RecycleView,虽说网络上比我写得好的太多了,小小纪录一下

    RefreshRecycleView.java

    import android.content.Context; import android.os.Handler; import android.os.Looper; import android.support.annotation.ColorRes; import android.support.annotation.IdRes; import android.support.annotation.Nullable; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import java.util.List; /** * 上拉刷新 下滑加载更多 * 暂时只支持 LinearLayoutManager * 原理: * 下滑 使用 SwipeRefreshLayout * 上拉 使用 屏幕上面的顶部item和顶部item相关,获取到RecyclerView列表中Item View的个数 * ---findFirstVisibleItemPosition(),findFirstCompletlyVisibleItemPosition() * ---findLastVisibleItemPosition(),findLastCompletlyVisibleItemPosition() * ---getItemCount() * Created by slack * on 17/3/8 下午1:58. * how to use : * 1.mRefreshRecycleView = (RefreshRecycleView) findViewById(R.id.xxx); * 2.mRefreshRecycleView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); * 3.mRefreshRecycleView.setAdapter(mContactsAdapter); */ public class RefreshRecycleView extends FrameLayout { private SwipeRefreshLayout mSwipeRefreshLayout; private RecyclerView mRecyclerView; private LinearLayoutManager mLinearLayoutManager; private RecyclerView.Adapter mAdapter; private Handler mHandler = new Handler(Looper.getMainLooper()); private RefreshListener mRefreshListener; private int mLastVisibleItemPosition;// 最后一个可见 item position public RefreshRecycleView(Context context) { this(context,null); } public RefreshRecycleView(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); } public RefreshRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(context); } /** * important !!! * RecyclerView.setLayoutManager * @param manager manager * @return */ public RefreshRecycleView setLayoutManager(LinearLayoutManager manager){ mLinearLayoutManager = manager; mRecyclerView.setLayoutManager(manager); return this; } /** * important !!! * RecyclerView.setAdapter * @param adapter adapter * @return */ public RefreshRecycleView setAdapter(RecyclerView.Adapter adapter){ mAdapter = adapter; mRecyclerView.setAdapter(adapter); return this; } /** * 异步需要手动 关闭 下拉 刷新 */ public void finishRefresh() { mHandler.post(new Runnable() { @Override public void run() { mAdapter.notifyDataSetChanged(); mSwipeRefreshLayout.setRefreshing(false); // } }); } /** * 设置进度条的颜色主题,最多设置四种 * @param colorResIds ids * @return */ public RefreshRecycleView setRefreshColorResources(@ColorRes int... colorResIds){ mSwipeRefreshLayout.setColorSchemeResources(colorResIds); return this; } /** * 设置滑动 刷新 监听 * @param l RefreshListener * @return */ public RefreshRecycleView setRefreshListener(RefreshListener l){ mRefreshListener = l; return this; } public RecyclerView getRecyclerView(){ return mRecyclerView; } private void initView(Context context) { mSwipeRefreshLayout = new SwipeRefreshLayout(context); mRecyclerView = new RecyclerView(context); mSwipeRefreshLayout.addView(mRecyclerView); addView(mSwipeRefreshLayout); initRefreshLayout(); initRecyclerView(); } private void initRecyclerView() { mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.setHasFixedSize(true); mRecyclerView.addOnScrollListener(mOnScrollListener); } private void initRefreshLayout() { /** * 设置刷新时动画的颜色,可以设置4个 */ mSwipeRefreshLayout.setColorSchemeResources( android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light); /** * 设置下拉监听,当用户下拉的时候会去执行回调 */ mSwipeRefreshLayout.setOnRefreshListener(mOnRefreshListener); /** * 这句话是为了,第一次进入页面的时候显示加载进度条 * 调整进度条距离屏幕顶部的距离 (boolean scale, int start, int end) */ mSwipeRefreshLayout.setProgressViewOffset( false, 0, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,24,getResources().getDisplayMetrics())); /** * setRefreshing(boolean refreshing) 设置SwipeRefreshLayout当前是否处于刷新状态, * 一般是在请求数据的时候设置为true,在数据被加载到View中后,设置为false。 */ } private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener = new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { if(mRefreshListener != null) { new Thread(new Runnable() { @Override public void run() { if(mRefreshListener.onPullToRefresh()) { finishRefresh(); } } }).start(); }else { finishRefresh(); } } }; private RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE && mLastVisibleItemPosition + 1 == mAdapter.getItemCount()) { if(mRefreshListener != null){ new Thread(new Runnable() { @Override public void run() { if(mRefreshListener.onUpGlideLoadMore()) { finishRefresh(); } } }).start(); }else { finishRefresh(); } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); mLastVisibleItemPosition = mLinearLayoutManager.findLastVisibleItemPosition(); } }; /** * 如果需要 上滑加载更多 的 布局 adapter need * extends this * extends ItemViewHolder * 原理 onCreateViewHolder(ViewGroup paren,int viewType) 第二个参数viewType,支持多套布局显示 */ public static abstract class RefreshFootAdapter<T extends RefreshFootAdapter.BaseViewHolder> extends RecyclerView.Adapter <T>{ private final int TYPE_ITEM =0; //普通 Item View private final int TYPE_FOOTER = 1; //底部 Foot View private final String FootViewTag = "FootView"; private List<?> mDatas ; protected LayoutInflater mLayoutInflater; private Context mContext; public RefreshFootAdapter(Context context, List<?> mDatas) { mContext = context; this.mDatas = mDatas; mLayoutInflater = LayoutInflater.from(context); } /** * 进行判断显示类型,来创建返回不同的View */ @Override public T onCreateViewHolder(ViewGroup parent, int viewType) { if(viewType==TYPE_ITEM){ return onItemView (parent, viewType); }else if(viewType==TYPE_FOOTER){ return onFootView(parent, viewType); } return null; } /** * return new ItemViewHolder(xxx) */ protected abstract T onItemView(ViewGroup parent, int viewType); /** * foot view */ protected abstract T onFootView(ViewGroup parent, int viewType); /** * 返回的Item数量在数据的基础上面+1,增加一项FootView布局项 */ @Override public int getItemCount() { return mDatas == null ? 1 : mDatas.size() + 1; } /** * 最后一个item设置为footerView * position 0,1,2,3... */ @Override public int getItemViewType(int position) { if (position + 1 == getItemCount()) { return TYPE_FOOTER; } else { return TYPE_ITEM; } } @Override public void onBindViewHolder(T holder, int position) { holder.bindView(holder,position); } public abstract class BaseViewHolder extends RecyclerView.ViewHolder{ private View mView; public BaseViewHolder(View itemView) { super(itemView); mView = itemView; } protected abstract void bindView(RecyclerView.ViewHolder holder,int pos); protected View findViewById(@IdRes int id){ return mView.findViewById(id); } } } /** * 方法都是在子线程里运行的 * return 是否 同步执行代码(true 同步获取数据,false 异步获取数据) * 异步需要手动 关闭 下拉 刷新 */ public interface RefreshListener{ boolean onPullToRefresh(); boolean onUpGlideLoadMore(); } }

    使用比较简单,直接把这个自定义文件拷贝了就好,需要注意的是 回调方法都是在 子线程里运行的,毕竟加载数据要么联网要么读取文件,不需要在主线程里执行,返回值的意思是判断是否在子线程里同步获取数据,

    如果异步获取 返回 false,数据获取到后需要主动调用 

    mRefreshRecycleView.finishRefresh();  刷新数据

    如何使用:

    final List<String> data = new ArrayList<String>(){ { for (int i= 0;i<20;i++){ add("item " + i); } } }; mRefreshRecycleView.setLayoutManager( new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); mRefreshRecycleView.setAdapter(new ReshAdapter(mRefreshRecycleView.getContext(),data)); mRefreshRecycleView.setRefreshListener(new RefreshRecycleView.RefreshListener() { @Override public boolean onPullToRefresh() { data.clear(); for (int i= 0;i<20;i++){ data.add("onPullToRefresh " + i); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return true; } @Override public boolean onUpGlideLoadMore() { for (int i= 0;i<5;i++){ data.add("onUpGlideLoadMore " + i); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return true; } });里面封装了一个adapter ,主要是处理上滑时没有界面,如果不需要上滑加载更多的提示界面,直接无视下面的内容

    自定义adapter extends RefreshRecycleView.RefreshFootAdapter  提供Item 布局 和 foot 提示正在加载数据的布局

    class ReshAdapter extends RefreshRecycleView.RefreshFootAdapter { private List<String> mDatas; ReshAdapter(Context context, List<String> datas) { super(context, datas); this.mDatas = datas; } @Override protected ReshViewHolder onItemView(ViewGroup parent, int viewType) { return new ReshViewHolder( mLayoutInflater.inflate(R.layout.item_contact,parent,false)); } @Override protected FootViewHolder onFootView(ViewGroup parent, int viewType) { return new FootViewHolder( mLayoutInflater.inflate(R.layout.item_contact,parent,false)); } class ReshViewHolder extends BaseViewHolder{ private TextView textView; public ReshViewHolder(View itemView) { super(itemView); textView = (TextView)findViewById(R.id.contact_name); } @Override protected void bindView(RecyclerView.ViewHolder holder, int pos) { textView.setText(mDatas.get(pos)); } } class FootViewHolder extends BaseViewHolder{ private TextView textView; public FootViewHolder(View itemView) { super(itemView); textView = (TextView)findViewById(R.id.contact_name); } @Override protected void bindView(RecyclerView.ViewHolder holder, int pos) { textView.setText("loading more ..."); } } }

    转载请注明原文地址: https://ju.6miu.com/read-3722.html

    最新回复(0)