Seçilen öğeyi üstte göstermek için RecyclerView


216

RecyclerViewSeçilen öğeyi en üstte göstermek için a kaydırmanın bir yolunu arıyorum .

Bir de ListViewben kullanarak bunu başardı scrollTo(x,y)ve ihtiyaç merkezli olmak o elemanın üst alma.

Gibi bir şey:

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

Sorun şu ki yöntem söylerken RecyclerViewkullanırken bir hata döndürürscrollTo

RecyclerView, mutlak bir konuma kaydırmayı desteklemez

RecyclerViewSeçilen öğeyi görünümün en üstüne koymak için a'yı nasıl kaydırabilirim ?

Yanıtlar:


406

LinearLayoutManagerVeya Staggered kullanıyorsanız, GridLayoutManagerher birinin , öğenin başlangıcından itibaren hem konumunu hem de başlangıcını alan bir scrollToPositionWithOffset yöntemi vardır, RecyclerViewbu da ihtiyacınız olanı başaracak gibi görünmektedir (ofseti 0 olarak ayarlamak) üste hizalanmalıdır).

Örneğin:

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

34
Birisi RecyclerView kaydırma konumunu geri yüklemek için buna ihtiyaç duyarsa, kaydırma konumlarını (scrollToPositionWithOffset yöntemi için iki argüman) şu şekilde kaydedebilirsiniz: int index = linearLayoutManager.findFirstVisibleItemPosition (); Görünüm v = linearLayoutManager.getChildAt (0); int top = (v == null)? 0: (v.getTop () - linearLayoutManager.getPaddingTop ());
DominicM

Bu konuda almak gibi görünmüyor ne zaman scrollToPosition çağırmak için? seçim dinleyicisi bağımsız görünümler üzerindeyse, (menajeri yöneticisine scrolToPosition çağırabilen) erişimi olan RecyclerView nesnesi bir öğenin seçildiği konusunda nasıl bilgilendirilir?
Nonos

@Nonos, kullandığınız LayoutManager'ı önce RecylerView.setLayoutManager () içinde saklayabilir ve daha sonra doğrudan erişebilirsiniz. Bunun gibi: LinearLayoutManager llm = new LinearLayoutManager (this); mRecyclerView.setLayoutManager (um); ... (daha sonra kodda) ... llm.scrollToPositionWithOffset (2, 20);
Niraj

19
En üste "düzgün" gitmek istersem ne olur?
Tiago

@Tiago, onunla oynamadım, ancak bu 3 bölümden oluşan makale dizisi yardımcı olabilir: blog.stylingandroid.com/scrolling-recyclerview-part-1
Niraj

93

Dikey LinearLayout Manager arıyorsanız, bir özel kullanarak düzgün kaydırma elde edebilirsiniz 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;
        }
    }
}

geri dönüşüm görünümünde layoutmanager örneğini kullandığınızda, arama recyclerView.smoothScrollToPosition(pos);işlemi seçili konuma geri dönüşüm görünümünün en üstüne kaydırılır


1
Gerçekten faydalı bir cevap! Ayrıca getHorizontalSnapPreference()Yatay listeler için TopSnappedSmoothScroller'da geçersiz kıldım.
Juan Saravia

6
Bunun sadece kalanları doldurmaya yetecek kadar / altında olan maddeler için işe yaradığını gözlemlemede haklı mıyım RecyclerView? - olursa olsun bu son kalemi için işin görünmüyor: Hangi demek ki sadece kaydırma öğesi altındaki görünür hale ama o tüm yol yukarı hareket etmiyor kadar. Bunu nasıl başaracağınıza dair bir fikrin var mı? (Ben özel dolgu ayarlayarak bu konuda çalıştı ama bu gerçekten doğru görünmüyor ...)SNAP_TO_STARTRecyclerViewRecyclerView
david.mihola


bazen öğe dosent odaklanmak, ben madde görünümü için çekilebilir bir odak yaşıyorum.
YLS

1
@ david.mihola 'Doğru' bir yol buldunuz mu? Benim geri dönüşüm görünümüne özel dolgu ayarladım ama bazı garip sorunlar yaşıyorum ...
bernardo.g


27

Sadece araman gerek recyclerview.scrollToPosition(position) . Bu iyi!

Bağdaştırıcıda çağırmak istiyorsanız, bağdaştırıcınızın yöntemi uygulayandan daha fazla geri dönüşüm görüntüleme örneği veya geri dönüşüm görüntüleme içeren etkinlik veya parçaya sahip olmasına izin verin getRecyclerview() .

Umarım size yardımcı olabilir.


2
Bu benim için çalıştı - recyclerView.scrollToPosition (0); beni zirveye koy.
Ray Hunter

2
çalışmıyorsa linearLayoutManager.scrollToPositionWithOffset (pos, 0) kullanmanız gerekir;
Anil Ugale

@Anil Ugale Bu saçmalık. Tabii ki işe yarıyor. RecyclerView için herhangi bir LayoutManager kullanabilirsiniz. Daha sonra kaydırmak istediğinizde neden ilgilenmelisiniz? Bence yanlış bir şey yapıyordun. Recyclerview.scrollToPosition (position), LayoutManager.scrollToPosition (position) öğesini çağıran bir kolaylık yöntemidir.
İnanılmaz Ocak

1
Her durumda çalışmaz mı, layoutManager genellikle sadece bilgileriniz için kaydırma işleminden sorumludur.
Muhammed

Bu, istenen öğeyi her zaman soru sorulduğu gibi en üste koymaz.
James Riordan

11

hız regülatörü ile aynı

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

Benim için neyin işe yaradığını dene!

Değişken oluşturma private static int displayedposition = 0;

Şimdi RecyclerView'ınızın Faaliyetinizdeki konumu için.

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();


            }
        });

Bu ifadeyi, görünümünüzde görüntülenen eski siteyi yerleştirmesini istediğiniz yere yerleştirin.

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

İşte bu, benim için iyi çalıştı \ o /


7

sadece bu yöntemi basitçe çağırın:

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

onun yerine:

recyclerView.scrollToPosition(yourItemPosition);

"onun yerine"? Distwo "scrollToPosition" dan bahsetmedi. Eğer kullansaydı hiçbir sorun olmazdı. scrollToPosition () istendiği gibi.
İnanılmaz Ocak

1
tuhaf bir şekilde, scrollToPositionWithOffset kullanarak benim için çalışıyor ve recyclerview.scrollToPosition işe yaramadı. Her ne kadar, ben yöntemlerin statik ve değil bir fikir verir, çünkü Amir recyclerView recyclerview değiştirmek için isterdim.
Mohit

6

tıklandığında RecyclerView yenilendikten sonra kaydırma konumunu geri yüklemek için ne yaptım:

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 nesnesini oluşturmadan önce ve ilk nesneyi oluşturduktan sonra LinearLayoutManager nesnesinin scrollToPositionWithOffset öğesi çağrıldı.


6

Neden en iyi cevabı bulamadım bilmiyorum ama bu gerçekten basit.

recyclerView.smoothScrollToPosition(position);

Hata yok

Animasyonlar Oluşturur


bunu faaliyete veya adaptöre nereye koyacaksınız?
Arnold Brown

3

belirli bir konuma kaydırın
ve bu bana çok yardımcı oldu. tıklama dinleyici ile adaptörünüzdeki pozisyonu alabilirsiniz

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

Yanıtların hiçbiri, son öğelerin en üstte nasıl gösterileceğini açıklamaz. Bu nedenle, yanıtlar yalnızca üzerinde veya altında kalan öğeleri doldurmaya yetecek kadar öğe bulunan öğeler için geçerlidir RecyclerView. Örneğin, 59 öğe varsa ve 56. öğe seçildiyse, aşağıdaki resimde olduğu gibi üstte olmalıdır:

RecyclerView - eleman 56 seçildi Biz kullanarak bu davalarını linearLayoutManager.scrollToPositionWithOffset(pos, 0)içine ve ek mantığı Adapteriçinde RecyclerView(son öğeyi görünür değilse o zaman yeterli alan dolgu var demektir son öğenin altına özel bir marj ekleyerek - RecyclerView). Özel kenar boşluğu, kök görünüm yüksekliği ile öğe yüksekliği arasında bir fark olabilir. Yani, sizin Adapteriçin RecyclerViewaşağıdaki gibi görünecektir:

...
@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

Benim durumumda RecyclerViewböyle bir dolgu topum var

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

Sonra bir öğeyi yukarı kaydırmak için

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

1

Eğer senin LayoutManagerolduğunu LinearLayoutManagerkullandığınız scrollToPositionWithOffset(position,0);üzerine ve listede öğe ilk görünür öğeyi yapacaktır. Aksi takdirde, kullanabilirsiniz smoothScrollToPositionüzerindeRecyclerView doğrudan.

Aşağıdaki kodu kullanarak sona erdi.

 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

Bir öğeyi (thisView) yukarı kaydırmak için aşağıdaki kodu kullanın.
Farklı yüksekliklere sahip GridLayoutManager için de çalışır:

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);

Hızlı bir çözüm için yeterince iyi çalışıyor gibi görünüyor.


1
Değeri nedir thisPosition?
12'de pRaNaY

yumuşak kaydırma yapmak istediğiniz konum
Jan Rabe

Neden herhangi bir hesaplama yapmadan smoothScrollToPosition (int position) kullanmıyorsunuz? Nereden başladığınız önemli değil, değil mi?
İnanılmaz Ocak
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.