Sur ListView, vous pouvez avoir un défilement rapide qui vous permet de faire glisser une barre de défilement pour faire défiler facilement où vous le souhaitez (en utilisant fastScrollEnabled attribut)
En association avec la classe " SectionIndexer " et éventuellement avec certains attributs, vous pouvez obtenir un Nice popup qui s'affiche lorsque vous utilisez cette barre de défilement (link here ).
Une telle chose est affichée sur l'application Contacts afin que vous puissiez facilement faire défiler des lettres spécifiques.
RecyclerView ne semble pas en avoir. Pas même un défilement rapide.
Comment ajouter une fonctionnalité de défilement rapide à RecyclerView?
Toutes les bibliothèques tierces ayant des problèmes, j'ai décidé de rassembler tout ce que je pouvais trouver (principalement de ici ), de tout réparer et de publier mon propre POC du défilement rapide de RecyclerView:
https://github.com/AndroidDeveloperLB/LollipopContactsRecyclerViewFastScroller
usage:
créez un objet RecyclerView.Adapter qui implémente BubbleTextGetter, qui donne une position dans les données retournera le texte à afficher dans le popup.
positionnez le FastScroller dans la présentation contenant le RecyclerView (probablement à la bonne zone).
Personnaliser le FastScroller FastScroller
Quelques inconvénients:
Code:
BubbleTextGetter
public interface BubbleTextGetter
{
String getTextToShowInBubble(int pos);
}
recycler_view_fast_scroller__fast_scroller.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);
}
}
}
Je suis tombé sur cette question il y a quelques jours lorsque je me suis retrouvé dans cette situation. Voici mon exemple d'implémentation de FastScroll for RecyclerView:
Essayez d’exécuter l’exemple d’application et parcourez le code pour voir une utilisation assez simple d’un simple widget RecyclerViewFastScroller. Il y a des informations sur github, mais je vais inclure l'utilisation de base ici pour un scroller rapide vertical.
Pour un exemple complet, reportez-vous à l'application exemple dans le référentiel .
Dans l'activité XML 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 avez configuré la mise en page par programme, connectez le défilement rapide au 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;
}
...
J'espère que cela t'aides!
EDIT: Ajout de la prise en charge des indicateurs de section de style Android-Lollipop! Découvrez l'implémentation de l'application exemple pour plus de détails.
La bibliothèque de support Android 26.0.0 prend désormais en charge fastScrollEnabled
Nouvel indicateur booléen fastScrollEnabled pour RecyclerView.
Si cette option est activée, les options fastScrollHorizontalThumbDrawable, fastScrollHorizontalTrackDrawable, fastScrollVerticalThumbDrawable et fastScrollVerticalTrackDrawable doivent être définies.
Exemple - https://Android.jlelse.eu/fast-scrolling-with-recyclerview-2b89d4574688
Vous pouvez également utiliser A-Z Fastscroll pour RecyclerView. C'est le style iOS.
https://github.com/code-computerlove/FastScrollRecyclerView/
Comment l'utiliser:
Android.support.v7.widget.RecyclerView
par com.codecomputerlove.fastscrollrecyclerviewdemo.FastScrollRecyclerView
getMapIndex()
. La fonction devrait renvoyer le mapIndex. Regardez dans calculateIndexesForName()
pour trouver l'inspiration sur la façon de le créer. Une fois créé, transmettez-le à l'adaptateur du constructeur.FastScrollRecyclerViewItemDecoration
et ajoutez-la sur votre RecyclerView FastScrollRecyclerViewItemDecoration decoration = new FastScrollRecyclerViewItemDecoration(this); mRecyclerView.addItemDecoration(decoration);
<dimen name="fast_scroll_overlay_text_size">100dp</dimen>
à votre fichier /values/dimens.xml
. C'est la taille en dp de la lettre superposéeLa fonctionnalité FastScroller est ajoutée à partir de la bibliothèque Android 26.0.0 pour RecyclerView
compiler la dépendance
compile 'com.Android.support:recyclerview-v7:26.1.0'
compile 'com.Android.support:design:26.1.0'
ajouter la dépendance à project.gradle
maven {
url "https://maven.google.com"
}
votre fichier recyclerview.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>
thumb.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>
line.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>
Vous pouvez essayer notre lib: https://github.com/FutureMind/recycler-fast-scroll . Il en est encore à ses débuts, mais il a été conçu spécifiquement pour traiter le problème de manque de cohérence rencontré avec d'autres bibliothèques. Il utilise un mécanisme un peu différent. Il supporte également LayoutManager horizontal et prendra également en charge les configurations multi-colonnes dans un proche avenir.
Edit: il y a quelques options de personnalisation soignées maintenant.
Il est prévu de mettre en œuvre des barres de défilement avec RecycleView
et sa LayoutManager
.
Par exemple: computeVerticalScrollExtent()
, computeVerticalScrollOffset()
et computeVerticalScrollRange()
peut fournir des informations permettant de toujours positionner un curseur de défilement vertical au bon endroit.
Ces méthodes existent également dans LayoutManager
pour la délégation des mesures réelles. Donc, l'implémentation LayoutManager
utilisée doit supporter ces mesures.
En outre, faites glisser le doigt sur le curseur de défilement peut être intercepté en remplaçant onInterceptTouchEvent()
of RecyclerView
. Et après avoir calculé le parchemin souhaité, scrollTo()
peut être appelé pour mettre à jour RecyclerView
.
Il suffit d’activer le défilement rapide et d’ajouter le pouce, suivi de la 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" />