Android如何在recyclerview上获取用户滚动到项目的当前位置

时间:2016-07-07 14:06:40

标签: android android-recyclerview

在我的RecyclerView我有一些项目,用户可以滚动并看到,现在我想保存这个位置并滚动后回来,这下面的代码总是返回0,我不能保存

recyclerMarketLists.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
    @Override
    public void onScrollChanged() {
        recyclerViewCurrentScrolledPosition = recyclerMarketLists.getScrollY();
        Log.e("Y: ", recyclerViewCurrentSceolledPosition + "");
    }
});

Logcat:

07-07 18:28:30.919 2124-2124/com.sample.presentationproject E/Y:: 0

9 个答案:

答案 0 :(得分:29)

您正在尝试获取有关错误对象的信息。它不是RecyclerView也不是Adapter责任,而是RecyclerView的LayoutManager。

我会建议添加ViewTreeObserver.OnScrollChangedListener()而不是通用RecyclerView.OnScrollListener,而是使用onScrollStateChanged(RecyclerView recyclerView, int newState)回调,它会为您提供newState,您应该使用SCROLL_STATE_IDLE获取它的位置。含义:

yourRecyclerView.getLayoutManager().findFirstVisibleItemPosition();
  

正如Rik van Velzen指出的那样,你可能需要施展你的   LayoutManagerLinearLayoutManagerGridLayoutManager   (您必须转换为正在使用的正确类型)才能访问这些内容   findVisibleXXXX()方法。

关于所说的回调方法。希望我能为你做到这一点,你可以在这里找到关于课程的文档:

RecyclerView.OnScrollListener

yigit's (Google) response on visible positions

答案 1 :(得分:10)

感谢解决方案 Joaquim Ley 。这有助于在不使用任何库的情况下创建recyclerView horizontal寻呼机。

初始recyclerView

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_vocabulary_list);

    // Set up the recyclerView with the sections adapter.
    mRecyclerView = findViewById(R.id.list);
    mRecyclerView.setItemAnimator(new DefaultItemAnimator());
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
    mRecyclerView.setAdapter(new VocabularyListAdapter<>(vocabularyList));
    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == RecyclerView.SCROLL_STATE_IDLE){
                int position = getCurrentItem();
                onPageChanged(position);
            }
        }
    });
    PagerSnapHelper snapHelper = new PagerSnapHelper();
    snapHelper.attachToRecyclerView(mRecyclerView);
}



public boolean hasPreview() {
   return getCurrentItem() > 0;
}

public boolean hasNext() {
    return mRecyclerView.getAdapter() != null &&
            getCurrentItem() < (mRecyclerView.getAdapter().getItemCount()- 1);
}

public void preview() {
    int position = getCurrentItem();
    if (position > 0)
        setCurrentItem(position -1, true);
}

public void next() {
    RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
    if (adapter == null)
        return;

    int position = getCurrentItem();
    int count = adapter.getItemCount();
    if (position < (count -1))
        setCurrentItem(position + 1, true);
}

private int getCurrentItem(){
    return ((LinearLayoutManager)mRecyclerView.getLayoutManager())
            .findFirstVisibleItemPosition();
}

private void setCurrentItem(int position, boolean smooth){
    if (smooth)
        mRecyclerView.smoothScrollToPosition(position);
    else
        mRecyclerView.scrollToPosition(position);
}

答案 2 :(得分:2)

我对MainActivity进行了7次更改,并获得了像素完美的结果。从其他Activity(例如DetailActivity)返回状态时,我的recyclerview总是会记住其先前状态。

第1步:像这样初始化layoutManager:

    // Initialize the layout manager
    moviePosterLayoutManager = (moviePosterRecyclerView.getLayoutManager() == null) ?
    new GridLayoutManager(this, numberOfColumns) :  moviePosterRecyclerView.getLayoutManager();
            // create a new layoutManager                       // reuse the existing layoutManager

步骤2: 在MainActivity类中,创建一个STATIC变量,以在活动之间进行转换时保持布局管理器的状态:

private static Parcelable layoutManagerState;

步骤3: 还要在MainActivity()内部创建此常量:

公共静态最终字符串KEY_LAYOUT_MANAGER_STATE =“ layoutManagerState”;

第4步: 在MainActivity的onCreate方法中,执行以下测试(即

protected void onCreate(@Nullable final Bundle savedInstanceState) {....

    if (layoutManagerState != null) {
        //moviePosterLayoutManager
        moviePosterLayoutManager.onRestoreInstanceState(layoutManagerState);
        moviePosterRecyclerView.setLayoutManager(moviePosterLayoutManager);

    } else {

        moviePosterRecyclerView.setLayoutManager(moviePosterLayoutManager);
        moviePosterRecyclerView.scrollToPosition(moviePosition);
                                 // the default position

    }

第5步: 在您的onSaveInstanceState方法中,请确保     将您的layoutManagerState保存为可打包文件,如下所示:

受保护的void onSaveInstanceState(Bundle outState){

   layoutManagerState = moviePosterLayoutManager.onSaveInstanceState();

    // Save currently selected layout manager.            
   outState.putParcelable(KEY_LAYOUT_MANAGER_STATE,layoutManagerState);
}

步骤6: 将类似的代码放在MainActivity的onResume()方法中:

protected void onResume() {
    super.onResume();


    if (layoutManagerState != null) {
        moviePosterLayoutManager.onRestoreInstanceState(layoutManagerState);
    }

}

步骤7: 请记住,所有这些代码都放置在我的MainActivity.java文件中。 要记住,layoutManager负责维护滚动条的滚动位置。 回收者视图。因此,保存layoutManager的状态至关重要。该代码可以 模块化并放置在自定义的recyclerview中,但是我发现这对我来说更简单 实施。

答案 3 :(得分:2)

这是Kotlin中的扩展功能:

private fun RecyclerView.getCurrentPosition() : Int {
    return (this.layoutManager as LinearLayoutManager?)!!.findFirstVisibleItemPosition()
}

您可以在RecyclerView上调用此功能来使用它:

val position = yourRecyclerView.getCurrentPosition()

答案 4 :(得分:2)

在 Kotlin 中试试这个:

myRecyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)
        val offset: Int = myRecyclerView.computeHorizontalScrollOffset()
        if (offset % myRecyclerView.width == 0) {
            val position: Int = offset / myRecyclerView.width
            Log.e("Current position is", position.toString())
        }
    }
})

答案 5 :(得分:1)

没有一个解决方案有效,我通过使用布局管理器实现了这一点。 这是recyclerview的扩展函数

fun RecyclerView.addScrollListener(onScroll: (position: Int) -> Unit) {
    var lastPosition = 0
    addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
            if (layoutManager is LinearLayoutManager) {
                val currentVisibleItemPosition =
                    (layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()

                if (lastPosition != currentVisibleItemPosition && currentVisibleItemPosition != RecyclerView.NO_POSITION) {
                    onScroll.invoke(currentVisibleItemPosition)
                    lastPosition = currentVisibleItemPosition
                }
            }
        }
    })
}

您可以在 recyclerview 上像这样使用它。

 campusFeedRv.addScrollListener { position: Int ->
            Log.d(TAG, "Current Position: $position ")
  }

答案 6 :(得分:0)

对于类似的要求以及需要在滚动状态更改时执行的某些操作,我使用自定义滚动侦听器进行了此操作:

class OnScrollListener(private val action: () -> Unit) : RecyclerView.OnScrollListener() {

private var actionExecuted: Boolean = false
private var oldScrollPosition: Int = 0

override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
    super.onScrollStateChanged(recyclerView, newState)
    when (newState) {
        RecyclerView.SCROLL_STATE_DRAGGING -> actionExecuted = false
        RecyclerView.SCROLL_STATE_SETTLING -> actionExecuted = false
        RecyclerView.SCROLL_STATE_IDLE -> {

            val scrolledPosition =
                (recyclerView.layoutManager as? LinearLayoutManager)?.findFirstVisibleItemPosition() ?: return

            if (scrolledPosition != RecyclerView.NO_POSITION && scrolledPosition != oldScrollPosition && !actionExecuted) {
                action.invoke()
                actionExecuted = true
                oldScrollPosition = scrolledPosition
            }

        }
    }
}

}

这是由于RecyclerView onScroll先前存在的错误,该错误恰好触发2-3次甚至更多次回调。而且,如果要执行某些操作,则最终将执行多次。

答案 7 :(得分:0)

    learnRecycleView
        .addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView,
                                   int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int offset=learnRecycleView.computeHorizontalScrollOffset();

                if (offset % learnRecycleView.getWidth() == 0) {
                    int position = offset / learnRecycleView.getWidth();
                    System.out.println("Current position is"+position);
                }
            }
        });

答案 8 :(得分:0)

就我而言,我需要在 Activity 中查看当前位置,因此我创建了一个回调方法并使用以下方法。

Adapter 类中添加此代码以获取视图的当前位置。

onBindViewHolder 方法中添加它。

holder.imgProductParts.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
            @Override
            public void onViewAttachedToWindow(View v) {
                onPositionChangeListener.onItemChanged(position);
            }

            @Override
            public void onViewDetachedFromWindow(View v) { }
        });