RecyclerView的滾動事件分析

列表的滾動通常分爲兩種:java

  1. 手指按下 -> 手指拖拽列表移動 -> 手指中止拖拽 -> 擡起手指sql

  2. 手指按下 -> 手指快速拖拽後擡起手指 -> 列表繼續滾動 -> 中止滾動markdown

從上面能夠看出,滾動狀態分爲:ide

|--靜止 |--滾動 |--被迫拖拽移動 |--本身滾動

上面的過程的狀態變化以下:this

  1. 靜止 -> 被迫拖拽移動 -> 靜止spa

  2. 靜止 -> 被迫拖拽移動 -> 本身滾動 -> 靜止code

<!--more-->component

監聽RecyclerView的滾動

好了,咱們分析完滾動的過程,再看看如何監聽RecyclerView的滾動.查看源碼是最好的方法.接口

看源碼

查看RecyclerView的源碼,咱們能夠看到如下代碼:coffeescript

/** * 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; } /** * Add a listener that will be notified of any changes in scroll state or position. * <p>Components that add a listener should take care to remove it when finished. * Other components that take ownership of a view may call {@link #clearOnScrollListeners()} * to remove all attached listeners.</p> * @param listener listener to set or null to clear */ public void addOnScrollListener(OnScrollListener listener) { if (mScrollListeners == null) { mScrollListeners = new ArrayList<>(); } mScrollListeners.add(listener); }

也就是說有兩種方式能夠監聽滾動事件:

  1. 其中 setOnScrollListener 已通過時( 設置的監聽器源碼以下:

    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. * <p> * 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){} }

    在滾動過程當中,此監聽器會回調兩個方法.

    onScrollStateChanged : 滾動狀態變化時回調
    onScrolled : 滾動時回調

    這二者的區別在於: 狀態與過程

    舉例子

    注 : 如下源碼可在最後的地址中找到.

    demoRv = (RecyclerView) findViewById(R.id.demo_rv);
    layoutManager = new LinearLayoutManager(this); demoRv.setLayoutManager(layoutManager); demoRv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); bookAdapter = new BookAdapter(); bookAdapter.fillList(MockService.getBookList()); demoRv.setAdapter(bookAdapter); demoRv.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); Log.i(TAG, "-----------onScrollStateChanged-----------"); Log.i(TAG, "newState: " + newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); Log.i(TAG, "-----------onScrolled-----------"); Log.i(TAG, "dx: " + dx); Log.i(TAG, "dy: " + dy); Log.i(TAG, "CHECK_SCROLL_UP: " + recyclerView.canScrollVertically(TAG_CHECK_SCROLL_UP)); Log.i(TAG, "CHECK_SCROLL_DOWN: " + recyclerView.canScrollVertically(TAG_CHECK_SCROLL_DOWN)); } });

    以上代碼中輸出了主要個幾個信息:

    1. newState : 目前的狀態

    2. dx : 水平滾動距離

    3. dy : 垂直滾動距離

    onScrollStateChanged 方法

  2. recyclerView : 當前在滾動的RecyclerView

  3. newState : 當前滾動狀態.

其中newState有三種值:

//中止滾動 public static final int SCROLL_STATE_IDLE = 0; //正在被外部拖拽,通常爲用戶正在用手指滾動 public static final int SCROLL_STATE_DRAGGING = 1; //自動滾動開始 public static final int SCROLL_STATE_SETTLING = 2;

onScrolled 方法

  • recyclerView : 當前滾動的view

  • dx : 水平滾動距離

  • dy : 垂直滾動距離

真機實踐

運行代碼

運行以上代碼,而後按照上面的滾動過程分別進行兩種滾動.

第一種方式緩慢滾動結果以下:

I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 1 I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: -6 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true ------------------------n個onScrolled-------------------- I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: -2 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: false I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 0

第二種快速滾動結果以下:

I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 1 I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 59 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true --------------------------n個onScrolled------------------- I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 54 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 2 I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 56 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true --------------------------n個onScrolled------------------- I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 14 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true I/MainActivity: -----------onScrolled----------- I/MainActivity: dx: 0 I/MainActivity: dy: 1 I/MainActivity: CHECK_SCROLL_UP: true I/MainActivity: CHECK_SCROLL_DOWN: true I/MainActivity: -----------onScrollStateChanged----------- I/MainActivity: newState: 0

分析結果

且在滾動過程當中發現:

1.滾動方向

dy > 0 時爲向上滾動
dy < 0 時爲向下滾動

2.回調過程

緩慢拖拽回調過程:

1. newState = RecyclerView.SCROLL_STATE_DRAGGING; 2. dy 屢次改變 3. newState = RecyclerView.SCROLL_STATE_IDLE

快速滾動回調過程:

1. newState = RecyclerView.SCROLL_STATE_DRAGGING; 2. dy 屢次改變 3. newState = RecyclerView.SCROLL_STATE_SETTLING; 4. dy 屢次改變 5. newState = RecyclerView.SCROLL_STATE_IDLE;

3.頂端與底部

以上信息中還打印了

RecyclerView.canScrollVertically(-1)的值表示是否滾動到頂部

封裝

基於以上,咱們能夠封裝一個能夠回調滾動狀態和方向的RecyclerView.

先創建事件監聽的接口public interface OnScrollCallback { void onStateChanged(ScrollRecycler recycler, int state); void onScrollUp(ScrollRecycler recycler, int dy); void onScrollDown(ScrollRecycler recycler, int dy); }

再寫一個類RecyclerView,在類中添加如下方法:

public void setOnScrollCallback(final OnScrollCallback callback) { if (callback == null) { return; } addOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); callback.onStateChanged(ScrollRecycler.this, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (dy > 0) { callback.onScrollDown(ScrollRecycler.this, dy); } else { callback.onScrollUp(ScrollRecycler.this, dy); } } }); }
相關文章
相關標籤/搜索