Comment ajouter un rouleau compresseur fast-scroller à la RecyclerView

arrière-plan

sur ListView, vous pouvez avoir un scroller rapide qui vous permet de glisser un scrollbar pour faire défiler facilement où vous voulez (en utilisant fastScrollEnabled attribut)

ensemble avec" SectionIndexer " classe et éventuellement quelques attributs, vous pourriez avoir un popup agréable qui montre que vous utilisez ce scrollbar (lien ici ).

une telle chose est affichée sur l'application contacts afin que vous puissiez faire défiler facilement des lettres spécifiques.

le problème

RecyclerView ne semble pas en avoir. Même pas un rapide de défilement.

la question

comment ajouter une fonctionnalité de scroller rapide pour le RecyclerView?

68
demandé sur Daniel Smith 2015-01-06 14:59:16

9 réponses

je suis tombé sur cette question il y a quelques jours quand je suis tombé dans cette situation. Voici mon exemple de mise en œuvre de FastScroll pour RecyclerView :

github.com/danoz73/RecyclerViewFastScroller

essayez d'exécuter l'application d'exemple, et parcourez le code pour voir une utilisation assez simple d'un widget RecyclerViewFastScroller simple. Il y a des informations sur github, mais je vais inclure la base l'utilisation ici pour une verticale rapide molette.

pour un exemple complet, reportez-vous à la exemple d'application dans le rapport .

Usage De Base

dans l'activité ou le fragment XML où réside votre RecyclerView, incluez un objet VerticalRecyclerViewFastScroller. L'exemple suivant serait dans une disposition relative:

...
  <android.support.v7.widget.RecyclerView
      android:id="@+id/recyclerView"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>


  <xyz.danoz.recyclerviewfastscroller.vertical.VerticalRecyclerViewFastScroller
      android:id="@+id/fast_scroller"
      android:layout_width="@dimen/however_wide_you_want_this"
      android:layout_height="match_parent"
      android:layout_alignParentRight="true"
    />
...

dans votre fragment ou activité où vous mettez en place la mise en page par programmation, le raccordement de la rapide molette pour le recycleur:

...
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View rootView = inflater.inflate(R.layout.recycler_view_frag, container, false);
      ...

      // Grab your RecyclerView and the RecyclerViewFastScroller from the layout
      RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
      VerticalRecyclerViewFastScroller fastScroller = (VerticalRecyclerViewFastScroller) rootView.findViewById(R.id.fast_scroller);

      // Connect the recycler to the scroller (to let the scroller scroll the list)
      fastScroller.setRecyclerView(recyclerView);

      // Connect the scroller to the recycler (to let the recycler scroll the scroller's handle)
      recyclerView.setOnScrollListener(fastScroller.getOnScrollListener());

      ...
      return rootView;
  }
...

Espérons que cette aide!

EDIT : il y a maintenant le soutien ajouté pour Android-Lollipop-Contacts-les indicateurs de section de style! Consultez l'exemple de mise en œuvre de l'application pour plus de détails.

52
répondu Daniel Smith 2015-02-25 12:33:09

étant donné que toutes les bibliothèques tierces avaient des problèmes, j'ai décidé de rassembler ce que je peux trouver (principalement à partir de ici ), corriger tout et publier mon propre POC du scroller rapide de la RecyclerView:

https://github.com/AndroidDeveloperLB/LollipopContactsRecyclerViewFastScroller

utilisation:

  1. faire un RecyclerView.Adaptateur qui met en œuvre BubbleTextGetter, qui donne une position dans les données retournera le texte à afficher dans la bulle-popup.

  2. placez le contrôleur rapide à l'intérieur de la disposition qui contient le RecyclerView (probablement à la bonne zone).

  3. personnaliser le FastScroller FastScroller

certains inconvénients:

  1. ne supporte pas le changement d'orientation, mais c'est probablement facile à réparer.
  2. ne supporte pas les autres managers de layout. Seulement Gestionnaire De Ligne
  3. nécessite API 11 et plus.

Code:

BubbleTextGetter

public interface BubbleTextGetter
  {
  String getTextToShowInBubble(int pos);
  }

recycleur_vue_fast_scroller__fast_molette.xml

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:tools="http://schemas.android.com/tools"
       android:layout_width="wrap_content"
       android:layout_height="match_parent">

  <TextView
    android:id="@+id/fastscroller_bubble"
    android:layout_gravity="right|end"
    android:gravity="center"
    android:textSize="48sp" tools:text="A"
    android:layout_width="wrap_content"
    android:textColor="#FFffffff"
    android:layout_height="wrap_content"
    android:background="@drawable/recycler_view_fast_scroller__bubble"
    android:visibility="visible"/>

  <ImageView
    android:id="@+id/fastscroller_handle"
    android:layout_width="wrap_content"
    android:layout_marginRight="8dp"
    android:layout_marginLeft="8dp"
    android:layout_height="wrap_content"
    android:src="@drawable/recycler_view_fast_scroller__handle"/>

</merge>

activité principale

...
fastScroller=(FastScroller)findViewById(R.id.fastscroller);
fastScroller.setRecyclerView(recyclerView);

FastScroller

public class FastScroller extends LinearLayout
  {
  private static final int BUBBLE_ANIMATION_DURATION=100;
  private static final int TRACK_SNAP_RANGE=5;

  private TextView bubble;
  private View handle;
  private RecyclerView recyclerView;
  private final ScrollListener scrollListener=new ScrollListener();
  private int height;

  private ObjectAnimator currentAnimator=null;

  public FastScroller(final Context context,final AttributeSet attrs,final int defStyleAttr)
    {
    super(context,attrs,defStyleAttr);
    initialise(context);
    }

  public FastScroller(final Context context)
    {
    super(context);
    initialise(context);
    }

  public FastScroller(final Context context,final AttributeSet attrs)
    {
    super(context,attrs);
    initialise(context);
    }

  private void initialise(Context context)
    {
    setOrientation(HORIZONTAL);
    setClipChildren(false);
    LayoutInflater inflater=LayoutInflater.from(context);
    inflater.inflate(R.layout.recycler_view_fast_scroller__fast_scroller,this,true);
    bubble=(TextView)findViewById(R.id.fastscroller_bubble);
    handle=findViewById(R.id.fastscroller_handle);
    bubble.setVisibility(INVISIBLE);
    }

  @Override
  protected void onSizeChanged(int w,int h,int oldw,int oldh)
    {
    super.onSizeChanged(w,h,oldw,oldh);
    height=h;
    }

  @Override
  public boolean onTouchEvent(@NonNull MotionEvent event)
    {
    final int action=event.getAction();
    switch(action)
      {
      case MotionEvent.ACTION_DOWN:
        if(event.getX()<handle.getX())
          return false;
        if(currentAnimator!=null)
          currentAnimator.cancel();
        if(bubble.getVisibility()==INVISIBLE)
          showBubble();
        handle.setSelected(true);
      case MotionEvent.ACTION_MOVE:
        setPosition(event.getY());
        setRecyclerViewPosition(event.getY());
        return true;
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_CANCEL:
        handle.setSelected(false);
        hideBubble();
        return true;
      }
    return super.onTouchEvent(event);
    }

  public void setRecyclerView(RecyclerView recyclerView)
    {
    this.recyclerView=recyclerView;
    recyclerView.setOnScrollListener(scrollListener);
    }

  private void setRecyclerViewPosition(float y)
    {
    if(recyclerView!=null)
      {
      int itemCount=recyclerView.getAdapter().getItemCount();
      float proportion;
      if(handle.getY()==0)
        proportion=0f;
      else if(handle.getY()+handle.getHeight()>=height-TRACK_SNAP_RANGE)
        proportion=1f;
      else
        proportion=y/(float)height;
      int targetPos=getValueInRange(0,itemCount-1,(int)(proportion*(float)itemCount));
      recyclerView.scrollToPosition(targetPos);
      String bubbleText=((BubbleTextGetter)recyclerView.getAdapter()).getTextToShowInBubble(targetPos);
      bubble.setText(bubbleText);
      }
    }

  private int getValueInRange(int min,int max,int value)
    {
    int minimum=Math.max(min,value);
    return Math.min(minimum,max);
    }

  private void setPosition(float y)
    {
    int bubbleHeight=bubble.getHeight();
    int handleHeight=handle.getHeight();
    handle.setY(getValueInRange(0,height-handleHeight,(int)(y-handleHeight/2)));
    bubble.setY(getValueInRange(0,height-bubbleHeight-handleHeight/2,(int)(y-bubbleHeight)));
    }

  private void showBubble()
    {
    AnimatorSet animatorSet=new AnimatorSet();
    bubble.setVisibility(VISIBLE);
    if(currentAnimator!=null)
      currentAnimator.cancel();
    currentAnimator=ObjectAnimator.ofFloat(bubble,"alpha",0f,1f).setDuration(BUBBLE_ANIMATION_DURATION);
    currentAnimator.start();
    }

  private void hideBubble()
    {
    if(currentAnimator!=null)
      currentAnimator.cancel();
    currentAnimator=ObjectAnimator.ofFloat(bubble,"alpha",1f,0f).setDuration(BUBBLE_ANIMATION_DURATION);
    currentAnimator.addListener(new AnimatorListenerAdapter()
    {
    @Override
    public void onAnimationEnd(Animator animation)
      {
      super.onAnimationEnd(animation);
      bubble.setVisibility(INVISIBLE);
      currentAnimator=null;
      }

    @Override
    public void onAnimationCancel(Animator animation)
      {
      super.onAnimationCancel(animation);
      bubble.setVisibility(INVISIBLE);
      currentAnimator=null;
      }
    });
    currentAnimator.start();
    }

  private class ScrollListener extends OnScrollListener
    {
    @Override
    public void onScrolled(RecyclerView rv,int dx,int dy)
      {
      View firstVisibleView=recyclerView.getChildAt(0);
      int firstVisiblePosition=recyclerView.getChildPosition(firstVisibleView);
      int visibleRange=recyclerView.getChildCount();
      int lastVisiblePosition=firstVisiblePosition+visibleRange;
      int itemCount=recyclerView.getAdapter().getItemCount();
      int position;
      if(firstVisiblePosition==0)
        position=0;
      else if(lastVisiblePosition==itemCount-1)
        position=itemCount-1;
      else
        position=firstVisiblePosition;
      float proportion=(float)position/(float)itemCount;
      setPosition(height*proportion);
      }
    }
  }
27
répondu android developer 2015-04-04 21:36:32

Il ya beaucoup de questions sans réponse sur RecyclerView et fast-scroll/indexeur de section , essayons de regrouper et de recueillir nos opinions et informations ici.

la réponse courte est: Non, vous ne pouvez pas activer le défilement rapide parce que RecyclerView ne contient pas un FastScroller " objet et Aucune variable liée à l'état logique. Cela parce que RecyclerView n'est pas un AbsListView .

d'un autre côté, il n'est pas impossible de mettre en œuvre un RecyclerView qui contient une version" dumped " de FastScroller et la logique nécessaire pour le défilement rapide, mais je n'ai pas vu aucune mise en œuvre de cela jusqu'à présent.

s'il vous plaît partagez votre considération à ce sujet ou si vous pensez que j'ai tort.

11
répondu bonnyz 2015-01-18 19:01:42

la bibliothèque de Soutien Android 26.0.0 prend maintenant en charge fastScrollEnabled

New fastScrollEnabled drapeau booléen pour RecyclerView.

si activé, fastScrollHorizontalThumbDrawable, fastscrolllhorizontaltrackdrawable, fastScrollVerticalThumbDrawable, et fastScrollVerticalTrackDrawable doivent être définis.

Sample - https://android.jlelse.eu/fast-scrolling-with-recyclerview-2b89d4574688

10
répondu Veeresh Charantimath 2017-08-31 09:34:47

vous pouvez aussi bien utiliser A-Z Fastscroll pour RecyclerView. C'est l'iOS style.

https://github.com/code-computerlove/FastScrollRecyclerView /

comment l'utiliser:

  • remplacer android.support.v7.widget.RecyclerView par com.codecomputerlove.fastscrollrecyclerviewdemo.FastScrollRecyclerView
  • votre adaptateur doit implémenter FastScrollRecyclerViewInterface et remplacer getMapIndex() . La fonction doit retourner le mapIndex. Regarder en calculateIndexesForName() pour l'inspiration sur la façon de le créer. Une fois créé passer à l'adaptateur dans le constructeur.
  • créer une instance de FastScrollRecyclerViewItemDecoration et l'ajouter sur votre RecyclerView FastScrollRecyclerViewItemDecoration decoration = new FastScrollRecyclerViewItemDecoration(this); mRecyclerView.addItemDecoration(decoration);
  • ajouter <dimen name="fast_scroll_overlay_text_size">100dp</dimen> à votre "151970920 de fichier". C'est la taille dp de la lettre superposée
3
répondu Flavius Mester 2015-07-08 06:58:22

vous pouvez essayer notre lib: https://github.com/FutureMind/recycler-fast-scroll . Il est encore en développement, mais a été construit spécifiquement pour traiter la question de smoothness que nous avons expérimenté avec d'autres bibliothèques. Il utilise un peu mécanisme différent. Il soutient LayoutManager horizontal aussi bien que et soutiendra également des configurations multi-colonnes dans un avenir proche.

Edit: il y a maintenant quelques options de personnalisation soignées.

3
répondu Michał K 2016-08-08 13:32:51

la fonctionnalité FastScroller est ajoutée de la bibliothèque android 26.0.0 pour RecyclerView

compiler dependency

    compile 'com.android.support:recyclerview-v7:26.1.0'
    compile 'com.android.support:design:26.1.0'

ajouter depedency au projet.gradle

     maven {
            url "https://maven.google.com"
        }

votre recyclerview.fichier xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    xmlns:tool="http://schemas.android.com/tools"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    tool:context=".MainActivity">
    <android.support.v7.widget.RecyclerView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:id="@+id/songlist"
                android:layout_marginStart="8dp"
                android:layout_marginEnd="8dp"
                app:fastScrollEnabled="true"
              app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
                app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
                app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
                app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
               /></LinearLayout>

pouce.xml

   <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">

    <corners
        android:topLeftRadius="44dp"
        android:topRightRadius="44dp"
        android:bottomLeftRadius="44dp"
        android:bottomRightRadius="44dp" />

    <padding
        android:paddingLeft="22dp"
        android:paddingRight="22dp" />

    <solid android:color="#f73831" />

</shape>

de ligne.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">

    <solid android:color="@color/dark_grey" />

    <padding
        android:top="10dp"
        android:left="10dp"
        android:right="10dp"
        android:bottom="10dp"/>
</shape>

thumb_drawable.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/thumb"
        android:state_focused="true"
        android:state_pressed="true" />

    <item android:drawable="@drawable/thumb"
        android:state_focused="false"
        android:state_pressed="true" />
    <item android:drawable="@drawable/thumb" 
            android:state_focused="true" />
    <item android:drawable="@drawable/thumb"
        android:state_focused="false"
        android:state_pressed="false" />
</selector>

line_drawble.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/line"
        android:state_focused="true"
        android:state_pressed="true" />

    <item android:drawable="@drawable/line"
        android:state_focused="false"
        android:state_pressed="true" />
    <item android:drawable="@drawable/line" 
            android:state_focused="true" />
    <item android:drawable="@drawable/line"
        android:state_focused="false"
        android:state_pressed="false" />
</selector>
3
répondu Abhishek Garg 2018-02-22 04:56:14

il y a une disposition d'application de barres de défilement avec RecycleView et son LayoutManager .

par exemple: computeVerticalScrollExtent() , computeVerticalScrollOffset() et computeVerticalScrollRange() peuvent fournir des informations pour toujours le positionnement d'un pouce de rouleau vertical à l'endroit correct.

ces méthodes sont également là dans LayoutManager pour la délégation réelle mesure. L'implémentation LayoutManager utilisée doit donc soutenir ces mesures.

aussi, drag touch on scroll thumb peut être intercepté en écrasant onInterceptTouchEvent() de RecyclerView . Et après avoir calculé le rouleau désiré, scrollTo() peut être appelé pour mettre à jour RecyclerView .

1
répondu S.D. 2015-02-12 19:04:51

il suffit d'activer le défilement rapide et ajouter pouce, tracker pour barre de défilement comme ci-dessous.

<android.support.v7.widget.RecyclerView
android:id="@+id/rv_sensors"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:fastScrollEnabled="true"
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable" />
0
répondu Maya Mohite 2018-08-07 07:19:21