Android - 在更改位置时,使用listener从recyclerview获取当前位置

时间:2017-10-09 19:34:46

标签: android android-recyclerview

我正在使用snaphelper使用recyclerview。 这是我的recyclerview:

    final LinearLayoutManager lm = new LinearLayoutManager(getContext(), 
    LinearLayoutManager.HORIZONTAL, false);

    recyclerview.setLayoutManager(lm);

    final PagerSnapHelper snapHelper = new PagerSnapHelper();
    snapHelper.attachToRecyclerView(recyclerview);

当用户滚动到另一个单元格时,我需要对新单元格位置执行某些操作。

这就是我要做的事情:

        recyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            if (newState != RecyclerView.SCROLL_STATE_IDLE) {
                return;
            }
            if recyclerview == null) {
                return;
            }
             //recyclerview.clearOnChildAttachStateChangeListeners();
            int firstVisible = ((LinearLayoutManager) viewerRv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
            if (firstVisible == RecyclerView.NO_POSITION) {
                return;
            }

          doSomething(firstVisible);
       }

问题是firstVisible var并不总是给我正确的位置,例如当我从位置0滚动到9时,这可以是输出: 0,1,2,3,4,4,5,9

还有另一种方法可以获得正确的当前位置吗?

最佳做法是什么?

4 个答案:

答案 0 :(得分:3)

这是我的解决方案:

        recyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            final int offset = topRv.computeHorizontalScrollOffset();
            if (offset % myCellWidth == 0) {
                final int position = offset / myCellWidth ;
            }
        }
    });

随时给我当前的位置。

答案 1 :(得分:1)

onScrollStateChanged(int state)的文档说明:

  • SCROLL_STATE_IDLE:没有滚动。

  • SCROLL_STATE_DRAGGING:用户在屏幕上拖动手指(或者以编程方式完成。

  • SCROLL_STATE_SETTLING:用户抬起手指,动画现在正在放慢速度。

当状态为SCROLL_STATE_DRAGGING或SCROLL_STATE_SETTLING时,您获得位置,显然这将返回回收器视图已滚动的所有位置。如果你想获得当前位置,你应该在recyclerview停止时获取(newState = SCROLL_STATE_IDLE)

您可以使用与此类似的代码来控制滚动的开始和结束:

boolean hasStarted = (state == SCROLL_STATE_DRAGGING);
boolean hasEnded = (state == SCROLL_STATE_IDLE);

所以最终的代码可能是这样的:

     //Initialize this variable on class that initialize recyclerview
     private boolean hasStarted;

   @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

      //Scroll is not start and user is dragging his finger  
      if(!hasStarted && newState == SCROLL_STATE_DRAGGING){
          hasStarted = true;
      }

      //If scroll starts and it finish
      if(hasStarted && newState == SCROLL_STATE_IDLE){
          //Restart variable for next iteration
          hasStarted = false;
          //Do something
          doSomething(firstVisible);
      }
   }

答案 2 :(得分:0)

在你的适配器中应该有一个名为

的方法
Max

谢谢, 阿南德

答案 3 :(得分:0)

用法

val recyclerView: RecyclerView = findViewById(R.id.myPagerRecyclerView)
val snapHelper: SnapHelper = PagerSnapHelper()
snapHelper.atttachToRecyclerView(snapHelper)

recyclerView.addOnScrollListener(SnapOnScrollListener(snapHelper, NOTIFY_ON_SCROLL) { position ->
        // Do what you want
}

实施

class SnapOnScrollListener(
        private val snapHelper: SnapHelper,
        var behavior: Int = NOTIFY_ON_SCROLL,
        var onSnapPositionChangeListener: ((position: Int) -> Unit)? = null
) : RecyclerView.OnScrollListener() {

    private var snapPosition = RecyclerView.NO_POSITION

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        if (behavior == NOTIFY_ON_SCROLL) {
            dispatchSnapPositionChange(recyclerView)
        }
    }

    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        if (behavior == NOTIFY_ON_SCROLL_STATE_IDLE
                && newState == RecyclerView.SCROLL_STATE_IDLE) {
            dispatchSnapPositionChange(recyclerView)
        }
    }

    private fun dispatchSnapPositionChange(recyclerView: RecyclerView) {
        val layoutManager = recyclerView.layoutManager ?: return
        val snapView = snapHelper.findSnapView(layoutManager) ?: return
        val snapPosition = layoutManager.getPosition(snapView)
        val snapPositionChanged = this.snapPosition != snapPosition
        if (snapPositionChanged) {
            onSnapPositionChangeListener?.invoke(snapPosition)
            this.snapPosition = snapPosition
        }
    }

    companion object {
        const val NOTIFY_ON_SCROLL = 0
        const val NOTIFY_ON_SCROLL_STATE_IDLE = 1
    }
}

值得称赞的消息来源和人

Detecting snap changes with Android’s RecyclerView SnapHelper by Christian Fregnam