Android(安卓)自定义RecyclerView.OnScrollListener,实现上拉分页加载、下拉刷新监听
Android 使用RecycleView实现吸附小标题的Demo(附源码)
Android 探究onCreateViewHolder和onBindViewHolder两者关系和调用次数
前言
上面两篇讲解了RecycleView创建和绑定子项的认识,特别是Recycleview的进行自定义子项装饰类ItemDecoration,实现了吸附标题的功能,其中涉及到了自定义View绘图技术点。
这篇,是想自定义RecyclerView.OnScrollListener 滑动监听,实现上拉分页加载、下拉刷新的功能。涉及的技术点是View的触摸事件传递与分发。我们知道事件类就是MotionEvent,这个类中包含了许多触摸事件,包括按下、抬起、滑动等。而且还可以通过这个类获取到事件的信息,比如事件发生的xy坐标值、类型、时间等。
GitHup ,此Demo代码地址:https://github.com/aiyangtianci/StickyDecoration
一、源码
1、OnScrollListener
public abstract static class OnScrollListener { /** * Callback method to be invoked when RecyclerView's scroll state changes. * * @param recyclerView The RecyclerView whose scroll state has changed. * @param newState The updated scroll state. One of {@link #SCROLL_STATE_IDLE}, * {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}. */ public void onScrollStateChanged(RecyclerView recyclerView, int newState){} /** * Callback method to be invoked when the RecyclerView has been scrolled. This will be * called after the scroll has completed. * * This callback will also be called if visible item range changes after a layout * calculation. In that case, dx and dy will be 0. * * @param recyclerView The RecyclerView which scrolled. * @param dx The amount of horizontal scroll. * @param dy The amount of vertical scroll. */ public void onScrolled(RecyclerView recyclerView, int dx, int dy){} }
可见,OnScrollListenerll类是一个什么类?“abstract”,即抽象类。我们知道,子类是必须实现父类的抽象方法。其中,onScrollStateChanged 、onScrolled不是抽象方法,有自己的方法体,无需子类必须实现。
onScrolled方法3个参数:1、recyclerView 是要被监听的列表;2、x坐标滑动值;3、y坐标滑动值。
onScrollStateChanged方法2个参数:1、recyclerView 是要被监听的列表;2、newState是滑动状态。
滑动状态值如下:(抬起、滑动中)
/** * The RecyclerView is not currently scrolling.当前未滚动。 */public static final int SCROLL_STATE_IDLE = 0;/** * The RecyclerView is currently being dragged by outside input such as user touch input. * 目前正在被外部输入拖拽,比如用户触摸输入。 */public static final int SCROLL_STATE_DRAGGING = 1;
2、RecyclerView.addOnScrollListener
/** * Set a listener that will be notified of any changes in scroll state or position. * * @param listener Listener to set or null to clear * * @deprecated Use {@link #addOnScrollListener(OnScrollListener)} and * {@link #removeOnScrollListener(OnScrollListener)} */ @Deprecated public void setOnScrollListener(OnScrollListener listener) { mScrollListener = listener; } public void addOnScrollListener(OnScrollListener listener) { if (mScrollListeners == null) { mScrollListeners = new ArrayList<>(); } mScrollListeners.add(listener); } public void removeOnScrollListener(OnScrollListener listener) { if (mScrollListeners != null) { mScrollListeners.remove(listener); } }
使用setOnScrollListener()方法时,注解会提示此方法即将被废弃的方法:
Inspection info: Reports where deprecated code is used in the specified inspection scope.所以,我们采用addOnScrollListener()方法将我们自定义的OnScrollListener类添加进去。
二、监听加载代码实现
我们可以通过onScrollStateChanged中的第1个参数RecycleView对象,拿到其布局管理类LayoutManager。我们看一下这个管理类的源码提供的方法,如下:
//最后一个可见item public int findLastCompletelyVisibleItemPosition() { final View child = findOneVisibleChild(getChildCount() - 1, -1, true, false); return child == null ? NO_POSITION : getPosition(child); } //第一个完全可见的item public int findFirstCompletelyVisibleItemPosition() { final View child = findOneVisibleChild(0, getChildCount(), true, false); return child == null ? NO_POSITION : getPosition(child); } public int getItemCount() {//拿到总数 final Adapter a = mRecyclerView != null ? mRecyclerView.getAdapter() : null; return a != null ? a.getItemCount() : 0; }
所以,我们可以通过LayoutManager拿到列表item的总数及列表前后完全显示的item,在滑动列表时会不断触发监听回调的方法,我们只需判断列表前后完全显示的item是否对应总数中item,如果判断通过就调用下拉、上拉的方法。
上拉、下拉的方法我们可以定义一个接口 UpPullOnScrollListener,在我们Activity中实现即可。
public interface UpPullOnScrollListener { /** * 加载更多数据的方法 */ public void onLoadMoreData() ; /** * 上拉刷新数据的方法 */ public void onRefreshData() ;}
自定义RecycleView滑动监听类:
public class UpPullRecyclerViewOnScrollListener extends RecyclerView.OnScrollListener { //监听回调 private UpPullOnScrollListener listener; public UpPullRecyclerViewOnScrollListener(UpPullOnScrollListener listener) { this.listener = listener; } /** * 标记是否正在向上滑动 */ boolean isUpPull = false; @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (newState == RecyclerView.SCROLL_STATE_IDLE) {//总数 int itemCount = manager.getItemCount();//最后显示的位置 int lastItemPosition = manager.findLastCompletelyVisibleItemPosition(); if (lastItemPosition == (itemCount - 1) && isUpPull) { listener.onLoadMoreData(); }//第一个显示的位置 int fristItemPosition = manager.findFirstCompletelyVisibleItemPosition(); if (fristItemPosition == (0) && !isUpPull){ listener.onRefreshData(); } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // 大于0表示正在向上滑动,小于等于0表示停止或向下滑动 isUpPull = dy > 0; }}
MainActivity 调用实现:
public class MainActivity extends AppCompatActivity{ RecyclerView mRecyclerView; RecyclerAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView =findViewById(R.id.recyclelist); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.setAdapter(mAdapter =new RecyclerAdapter(this, data.getDataList())); mRecyclerView.addOnScrollListener(new UpPullRecyclerViewOnScrollListener(onScrollListener)); } private UpPullOnScrollListener onScrollListener = new UpPullOnScrollListener() { @Override public void onLoadMoreData() { Toast.makeText(MainActivity.this, "上拉更新了 ", Toast.LENGTH_SHORT).show(); } @Override public void onRefreshData() { Toast.makeText(MainActivity.this, "下拉刷新了 ", Toast.LENGTH_SHORT).show(); } };}
三、SwipeRefreshLayout下拉刷新
由于,下拉刷新Android有自带的加载控件SwipeRefreshLayout,这里也是非常推荐大家去使用的。其用法也非常方便,这里简单说一下就好。
1、首先,在布局中使用,包裹RecycView
2、Java代码中,进行设置圈圈颜色和监听。(这里延迟3秒为了看效果)
SwipeRefreshLayout mSwipe = (SwipeRefreshLayout)findViewById(R.id.swiperefresh); mSwipe.setColorSchemeColors(Color.RED,Color.BLUE,Color.GREEN); mSwipe.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { mSwipe.setRefreshing(false); Toast.makeText(MainActivity.this, "下拉更新了 ", Toast.LENGTH_SHORT).show(); } },3000); } });
GitHup ,此Demo代码地址:https://github.com/aiyangtianci/StickyDecoration
更多相关文章
- launcher修改--获取屏幕缩略(预览)图
- Android(安卓)Studio Error: null, Cannot fit requested classe
- android 退出整个程序
- Android中Log信息的输出方法
- Android(安卓)Asynchronous Http Client-Android异步网络请求客
- Android异步加载图像(含线程池,缓存方法)
- Android(安卓)更新UI的两种方法——handler和runOnUiThread() -
- Android(安卓)仿QQ好友列表功能实现
- Android(安卓)RecyclerView简单运用