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?
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.
é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:
-
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.
-
placez le contrôleur rapide à l'intérieur de la disposition qui contient le RecyclerView (probablement à la bonne zone).
-
personnaliser le FastScroller FastScroller
certains inconvénients:
- ne supporte pas le changement d'orientation, mais c'est probablement facile à réparer.
- ne supporte pas les autres managers de layout. Seulement Gestionnaire De Ligne
- 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);
}
}
}
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.
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
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
parcom.codecomputerlove.fastscrollrecyclerviewdemo.FastScrollRecyclerView
- votre adaptateur doit implémenter FastScrollRecyclerViewInterface et remplacer
getMapIndex()
. La fonction doit retourner le mapIndex. Regarder encalculateIndexesForName()
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 RecyclerViewFastScrollRecyclerViewItemDecoration 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
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.
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>
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
.
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" />