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

更多相关文章

  1. launcher修改--获取屏幕缩略(预览)图
  2. Android(安卓)Studio Error: null, Cannot fit requested classe
  3. android 退出整个程序
  4. Android中Log信息的输出方法
  5. Android(安卓)Asynchronous Http Client-Android异步网络请求客
  6. Android异步加载图像(含线程池,缓存方法)
  7. Android(安卓)更新UI的两种方法——handler和runOnUiThread() -
  8. Android(安卓)仿QQ好友列表功能实现
  9. Android(安卓)RecyclerView简单运用

随机推荐

  1. Android(安卓)使用Theme实现动态切换主题
  2. Android简明开发教程十九:线程 Bezier曲线
  3. android中使用线程池和临时缓存优化网络
  4. 【Android(安卓)4.0】Android(安卓)Icon
  5. Android常用异常及解决方案
  6. Android(安卓)NDK简介
  7. 基于 Android(安卓)NDK 的学习之旅-----H
  8. Android(安卓)轻松实现语音识别
  9. 在windows下使用cmd命令通过adb shell自
  10. Android--创建和使用数据库详细指南