40

水平スクロール可能な を実装しましたRecyclerView。私RecyclerViewは aLinearLayoutManagerを使用していますが、私が直面している問題は、scrollToPosition(position)orsmoothScrollToPosition(position)または fromを使用しようとしたときLinearLayoutManagerですscrollToPositionWithOffset(position)。どちらも私にはうまくいきません。スクロール呼び出しが目的の場所にスクロールしないか、OnScrollListener.

これまで、さまざまなコードの組み合わせを試してきたので、ここにすべてを掲載することはできません。以下は私のために働くものです(しかし部分的にのみ):

public void smoothUserScrollTo(final int position) {

    if (position < 0 || position > getAdapter().getItemCount()) {
        Log.e(TAG, "An attempt to scroll out of adapter size has been stopped.");
        return;
    }

    if (getLayoutManager() == null) {
        Log.e(TAG, "Cannot scroll to position a LayoutManager is not set. " +
                "Call setLayoutManager with a non-null layout.");
        return;
    }

    if (getChildAdapterPosition(getCenterView()) == position) {
        return;
    }

    stopScroll();

    scrollToPosition(position);

    if (lastScrollPosition == position) {

        addOnLayoutChangeListener(new OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {

                if (left == oldLeft && right == oldRight && top == oldTop && bottom == oldBottom) {
                    removeOnLayoutChangeListener(this);

                    updateViews();

                    // removing the following line causes a position - 3 effect.
                    scrollToView(getChildAt(0));
                }
            }
        });
    }

    lastScrollPosition = position;
}

@Override
public void scrollToPosition(int position) {
    if (position < 0 || position > getAdapter().getItemCount()) {
        Log.e(TAG, "An attempt to scroll out of adapter size has been stopped.");
        return;
    }

    if (getLayoutManager() == null) {
        Log.e(TAG, "Cannot scroll to position a LayoutManager is not set. " +
                "Call setLayoutManager with a non-null layout.");
        return;
    }

//      stopScroll();

        ((LinearLayoutManager) getLayoutManager()).scrollToPositionWithOffset(position, 0);
//        getLayoutManager().scrollToPosition(position);
    }

このscrollToPositionWithOffset()ため選択しましたが、GridLayoutManager の代わりに LinearLayoutManager を使用しているため、おそらくケースが異なります。しかし、解決策は私にも有効ですが、先ほど述べたように、部分的にしか機能しません。

  • スクロールの呼び出しが 0 番目の位置から totalSize - 7 までの場合、スクロールは魅力的に機能します。
  • スクロールが totalSize - 7 から totalSize - 3 の場合、初めてリストの最後の 7 番目の項目までスクロールします。2回目ですが、うまくスクロールできます
  • totalSize - 3 から totalSize までスクロールすると、予期しない動作が発生し始めます。

誰かが回避策を見つけた場合は、感謝します。私のカスタムコードの要点はReyclerViewのとおりです。

4

18 に答える 18

58

私は数週間前に同じ問題を抱えていましたが、それを解決するための本当に悪い解決策しか見つかりませんでした. 200〜300ミリ秒で使用する必要がありましたpostDelayed

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        yourList.scrollToPosition(position);
    }
}, 200);

より良い解決策を見つけた場合は、お知らせください。幸運を!

于 2016-04-05T12:33:54.980 に答える
8

LinearSmoothScroller私の場合、これを毎回使用できます。

  1. 最初に LinearSmoothScroller のインスタンスを作成します。
  LinearSmoothScroller smoothScroller=new LinearSmoothScroller(activity){
            @Override
            protected int getVerticalSnapPreference() {
                return LinearSmoothScroller.SNAP_TO_START;
            }
        };
  1. そして、リサイクラー ビューを任意の位置にスクロールする場合は、次のようにします。
smoothScroller.setTargetPosition(pos);  // pos on which item you want to scroll recycler view
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);

終わり。

于 2019-05-17T07:34:28.267 に答える
0

以下のソリューションを使用して、リサイクラー ビューがリロードされた後 (向きの変更など)、リサイクラー ビューで選択したアイテムを表示します。LinearLayoutManager をオーバーライドし、onSaveInstanceState を使用て現在のリサイクラーの位置を保存します。次にonRestoreInstanceStateで、保存された位置が復元されます。最後に、onLayoutCompletedで、scrollToPosition(mRecyclerPosition)を使用して、以前に選択したリサイクラーの位置を再び表示しますが、Robert Banyai が述べたように、確実に機能させるには一定の遅延を挿入する必要があります。scrollToPosition が呼び出される前に、アダプターがデータをロードするのに十分な時間を提供する必要があると思います。

private class MyLayoutManager extends LinearLayoutManager{
    private boolean isRestored;

    public MyLayoutManager(Context context) {
        super(context);
    }

    public MyLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public MyLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void onLayoutCompleted(RecyclerView.State state) {
        super.onLayoutCompleted(state);
        if(isRestored && mRecyclerPosition >-1) {
            Handler handler=new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    MyLayoutManager.this.scrollToPosition(mRecyclerPosition);
                }
            },200);

        }
        isRestored=false;
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable savedInstanceState = super.onSaveInstanceState();
        Bundle bundle=new Bundle();
        bundle.putParcelable("saved_state",savedInstanceState);
        bundle.putInt("position", mRecyclerPosition);
        return bundle;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        Parcelable savedState = ((Bundle)state).getParcelable("saved_state");
        mRecyclerPosition = ((Bundle)state).getInt("position",-1);
        isRestored=true;
        super.onRestoreInstanceState(savedState);
    }
}
于 2017-11-27T01:16:21.553 に答える
0

答えは、Post メソッドを使用することです。これにより、すべてのアクションの正しい実行が保証されます。

于 2020-08-24T17:12:44.110 に答える