RecyclerViewをスクロールして、選択したアイテムを上部に表示します


215

スクロールしRecyclerViewて、選択したアイテムを一番上に表示する方法を探しています。

ListView、私は使用してそれを行うことができたscrollTo(x,y)し、必要がセンタリングされることを要素の上を取得します。

何かのようなもの:

@Override
public void onItemClick(View v, int pos){
    mylistView.scrollTo(0, v.getTop());
}

問題は、メソッドのRecyclerView使用時にエラーが返されることですscrollTo

RecyclerViewは絶対位置へのスクロールをサポートしていません

スクロールしRecyclerViewて、選択したアイテムをビューの一番上に配置するにはどうすればよいですか?

回答:


405

LinearLayoutManagerまたはStaggered を使用している場合GridLayoutManager、それぞれにscrollToPositionWithOffsetメソッドがありRecyclerView、これはの開始からのアイテムの開始の位置とオフセットの両方を取得します。これは、必要なことを達成するようです(オフセットを0に設定)上に揃える必要があります)。

例えば:

//Scroll item 2 to 20 pixels from the top
linearLayoutManager.scrollToPositionWithOffset(2, 20);

34
RecyclerViewのスクロール位置を復元するために誰かがこれを必要とする場合、これはスクロール位置(メソッドscrollToPositionWithOffsetの2つの引数)を保存する方法です。int index = linearLayoutManager.findFirstVisibleItemPosition(); ビューv = linearLayoutManager.getChildAt(0); int top =(v == null)?0:(v.getTop()-linearLayoutManager.getPaddingTop());
DominicM 2015

これについて私が理解していないように見えるのは scrollToPositionを呼び出すタイミングです。選択リスナーが個々のビューにある場合、RecyclerViewオブジェクト(scrolToPositionを呼び出すことができるレイアウトマネージャーにアクセスできる)は、アイテムが選択されたことをどのように通知されますか?
Nonos

@Nonosまず、RecylerView.setLayoutManager()で使用するLayoutManagerを保存してから、直接アクセスできます。このように:LinearLayoutManager llm = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(llm); ...(コードの後半)... llm.scrollToPositionWithOffset(2、20);
Niraj

19
「スムーズに」一番上までスクロールしたい場合はどうすればよいですか?
ティアゴ2015

@ティアゴ、私はそれで遊んでいませんが、この3部シリーズの記事は役立つかもしれません:blog.stylingandroid.com/scrolling-recyclerview-part-1
Niraj

93

垂直のLinearLayout Managerを探している場合は、カスタムを使用してスムーズなスクロールを実現できますLinearSmoothScroller

import android.content.Context;
import android.graphics.PointF;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;

public class SnappingLinearLayoutManager extends LinearLayoutManager {

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

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                       int position) {
        RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }

    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
        public TopSnappedSmoothScroller(Context context) {
            super(context);

        }

        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return SnappingLinearLayoutManager.this
                    .computeScrollVectorForPosition(targetPosition);
        }

        @Override
        protected int getVerticalSnapPreference() {
            return SNAP_TO_START;
        }
    }
}

リサイクルビューでlayoutmanagerのインスタンスを使用してから、呼び出しをrecyclerView.smoothScrollToPosition(pos);行うと、 選択した位置までスムーズにスクロールして、リサイクルビューの上部に移動します。


1
本当に役立つ答え!getHorizontalSnapPreference()水平リストのTopSnappedSmoothScroller もオーバーライドします。
ファンサラビア、2015年

6
これは、残りのアイテムを埋めるのに十分な数のアイテムがある場合にのみ機能することを確認してRecyclerViewよろしいですか?つまり、これは最後のアイテムでは機能しないようです- アイテムが一番下に表示されるまでスクロールしてSNAP_TO_STARTいるRecyclerViewだけであるにもかかわらず、上に移動しません。これを達成する方法のアイデアはありますか?(私はカスタムパディングを設定することでこれにRecyclerView
対処


アイテムがフォーカスされていることがありますが、アイテムビューに描画可能なフォーカスがあります。
YLS 2017年

1
@ david.mihola「正しい」方法を見つけましたか?カスタムパディングをrecyclerviewに設定しましたが、奇妙な問題が発生しています...
bernardo.g


28

あなただけを呼び出す必要がありますrecyclerview.scrollToPosition(position)。それはいいです!

アダプターでそれを呼び出す場合は、アダプターにrecyclerviewのインスタンス、またはrecyclerviewを含むアクティビティまたはフラグメントをgetRecyclerview()持たせ、それらにメソッドを実装します。

お役に立てれば幸いです。


2
これは私のために働きました-recyclerView.scrollToPosition(0); 私を一番上に置きます。
レイハンター

2
機能しない場合は、linearLayoutManager.scrollToPositionWithOffset(pos、0);を使用する必要があります。
Anil Ugale 2017年

@アニルウガレそれはナンセンスです。もちろん動作します。RecyclerViewには任意のLayoutManagerを使用できます。スクロールするときに、後で気にする必要があるのはなぜですか。あなたは何か間違ったことをしていたと思います。Recyclerview.scrollToPosition(position)は、LayoutManager.scrollToPosition(position)を呼び出す便利なメソッドです。
信じられないほどのヤン

1
@TheincredibleJanすべてのケースで機能するわけではありません。layoutManagerは一般に、情報のスクロールのみを担当します。
Mohammed

11

スピードレギュレーターと同じ

public class SmoothScrollLinearLayoutManager extends LinearLayoutManager {
private static final float MILLISECONDS_PER_INCH = 110f;
private Context mContext;

public SmoothScrollLinearLayoutManager(Context context,int orientation, boolean reverseLayout) {
    super(context,orientation,reverseLayout);
    mContext = context;
}

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                   int position) {
    RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext()){
        //This controls the direction in which smoothScroll looks for your view
        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return new PointF(0, 1);
        }

        //This returns the milliseconds it takes to scroll one pixel.
        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
            return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
        }
    };
    smoothScroller.setTargetPosition(position);
    startSmoothScroll(smoothScroller);
}


private class TopSnappedSmoothScroller extends LinearSmoothScroller {
    public TopSnappedSmoothScroller(Context context) {
        super(context);

    }

    @Override
    public PointF computeScrollVectorForPosition(int targetPosition) {
        return SmoothScrollLinearLayoutManager.this
                .computeScrollVectorForPosition(targetPosition);
    }

    @Override
    protected int getVerticalSnapPreference() {
        return SNAP_TO_START;
    }
}
}

8

私のために何がうまくいったか試してみてください!

変数を作成する private static int displayedposition = 0;

次に、アクティビティでのRecyclerViewの位置について説明します。

myRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                LinearLayoutManager llm = (LinearLayoutManager) myRecyclerView.getLayoutManager();


                displayedposition = llm.findFirstVisibleItemPosition();


            }
        });

このステートメントを、ビューに表示されていた以前のサイトを配置する場所に配置します。

LinearLayoutManager llm = (LinearLayoutManager) mRecyclerView.getLayoutManager();
        llm.scrollToPositionWithOffset(displayedposition , youList.size());

まあ、それだけです、私にとってはうまくいきました\ o /


7

このメソッドを呼び出すだけです:

((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(yourItemPosition,0);

の代わりに:

recyclerView.scrollToPosition(yourItemPosition);

"の代わりに"?Distwoは「scrollToPosition」については言及していません。もし彼がそれを使っていたなら、何の問題もなかっただろう。意図したとおりにscrollToPosition()。
信じられないほどの月

1
不思議なことに、scrollToPositionWithOffsetを使用するとうまくいきましたが、recyclerview.scrollToPositionはうまくいきませんでした。とはいえ、メソッドが静的でありそうでないという感覚を与えるため、AmirにRecyclerViewをrecyclerviewに変更するように要求します。
Mohit 2018年

6

クリックしたボタンのRecyclerViewを更新した後、スクロール位置を復元するために私がしたこと:

if (linearLayoutManager != null) {

    index = linearLayoutManager.findFirstVisibleItemPosition();
    View v = linearLayoutManager.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - linearLayoutManager.getPaddingTop());
    Log.d("TAG", "visible position " + " " + index);
}

else{
    index = 0;
}

linearLayoutManager = new LinearLayoutManager(getApplicationContext());
linearLayoutManager.scrollToPositionWithOffset(index, top);

linearLayoutManagerオブジェクトを作成する前に上から最初の可視アイテムのオフセットを取得し、それをインスタンス化した後、LinearLayoutManagerオブジェクトのscrollToPositionWithOffsetを呼び出しました。


6

なぜ私が最良の答えを見つけられなかったのか分かりませんが、それは本当に簡単です。

recyclerView.smoothScrollToPosition(position);

エラーなし

アニメーションを作成します


これをアクティビティまたはアダプターのどこに配置しますか?
アーノルドブラウン

3

特定の位置でスクロールして
、これは私をたくさん助けました。クリックリスナーにより、アダプターの位置を取得できます

layoutmanager.scrollToPosition(int position);

3
If you want to scroll automatic without show scroll motion then you need to write following code:

**=> mRecyclerView.getLayoutManager().scrollToPosition(position);**

If you want to display scroll motion then you need to add following code.
=>Step 1: You need to declare SmoothScroller.

RecyclerView.SmoothScroller smoothScroller = new
                LinearSmoothScroller(this.getApplicationContext()) {
                    @Override
                    protected int getVerticalSnapPreference() {
                        return LinearSmoothScroller.SNAP_TO_START;
                    }
                };

=>step 2: You need to add this code any event you want to perform scroll to specific position.
=>First you need to set target position to SmoothScroller.

**smoothScroller.setTargetPosition(position);**

=>Then you need to set SmoothScroller to LayoutManager.
                        **mRecyclerView.getLayoutManager().startSmoothScroll(smoothScroller);**

3

最後の項目を上部に表示する方法を説明する回答はありません。したがって、答えは、残りのアイテムを満たすためにアイテムの上または下にまだ十分なアイテムがあるアイテムに対してのみ機能しますRecyclerView。たとえば、59個の要素があり、56番目の要素が選択されている場合、次の図のように、それが一番上にあるはずです。

RecyclerView-要素56が選択されています最後のアイテムの下にカスタムマージンを追加することでlinearLayoutManager.scrollToPositionWithOffset(pos, 0)、追加のロジックを 使用してこれらのケースを処理できます(最後のアイテムが表示されない場合は、十分なスペースがあることを意味します)。カスタムマージンは、ルートビューの高さとアイテムの高さの差である可能性があります。したがって、for は次のようになります。AdapterRecyclerViewRecyclerView AdapterRecyclerView

...
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
    ...

    int bottomHeight = 0;
    int itemHeight = holder.itemView.getMeasuredHeight();
    // if it's the last item then add a bottom margin that is enough to bring it to the top
    if (position == mDataSet.length - 1) {
        bottomHeight = Math.max(0, mRootView.getMeasuredHeight() - itemHeight);
    }
    RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)holder.itemView.getLayoutParams();
    params.setMargins(0, 0, params.rightMargin, bottomHeight);
    holder.itemView.setLayoutParams(params);

    ...
} 
...

2

私の場合、私RecyclerViewはこのようなパディングトップを持っています

<android.support.v7.widget.RecyclerView
     ...
     android:paddingTop="100dp"
     android:clipToPadding="false"
/>

次に、アイテムを一番上までスクロールするには、

recyclerViewLinearLayoutManager.scrollToPositionWithOffset(position, -yourRecyclerView.getPaddingTop());

1

あなたLayoutManagerLinearLayoutManagerそれを使用scrollToPositionWithOffset(position,0);している場合、それはあなたのアイテムをリストの最初の目に見えるアイテムにします。それ以外の場合はsmoothScrollToPositionRecyclerView直接使用できます。

以下のコードを使用してしまいました。

 RecyclerView.LayoutManager layoutManager = mainList.getLayoutManager();
        if (layoutManager instanceof LinearLayoutManager) {
            // Scroll to item and make it the first visible item of the list.
            ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(position, 0);
        } else {
            mainList.smoothScrollToPosition(position);
        }

-2

以下のコードを使用して、アイテム(thisView)をスムーズに上にスクロールします。
高さの異なるビューを持つGridLayoutManagerでも機能します。

View firstView = mRecyclerView.getChildAt(0);
int toY = firstView.getTop();
int firstPosition = mRecyclerView.getChildAdapterPosition(firstView);
View thisView = mRecyclerView.getChildAt(thisPosition - firstPosition);
int fromY = thisView.getTop();

mRecyclerView.smoothScrollBy(0, fromY - toY);

迅速な解決策としては十分に機能するようです。


1
の価値はthisPosition何ですか?
pRaNaY 2016年

スムーズにスクロールしたい位置です
Jan Rabe

何も計算せずに、smoothScrollToPosition(int position)を使用しないのはなぜですか?どこから始めてもかまいません。
信じられないほどのヤン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.