web-dev-qa-db-ja.com

RecyclerViewに高速スクロールを追加する方法

バックグラウンド

リストビューでは、スクロールバーをドラッグして希望する場所に簡単にスクロールできる高速スクローラーを使用できます( fastScrollEnabled =属性)

SectionIndexer 」クラスおよびオプションでいくつかの属性と一緒に、このスクロールバーを使用すると表示されるニースポップアップを作成できます(リンク herehere ).

このようなことが連絡先アプリに表示されるため、特定の文字に簡単にスクロールできます。

問題

RecyclerViewにはこれらのいずれも含まれていないようです。高速スクロールでさえありません。

質問

RecyclerViewに高速スクローラー機能を追加するにはどうすればよいですか?

70

すべてのサードパーティライブラリに問題があるため、見つけることができるものを収集することにしました(主に here )、修正すべて、RecyclerViewの高速スクローラーのPOCを公開します。

https://github.com/AndroidDeveloperLB/LollipopContactsRecyclerViewFastScroller

使用法:

  1. bubbleTextGetterを実装するRecyclerView.Adapterを作成します。これは、データ内の位置を指定すると、バブルポップアップに表示するテキストを返します。

  2. fastScrollerをRecyclerViewを収容するレイアウト内に配置します(おそらく右側の領域)。

  3. FastScroller FastScrollerをカスタマイズする

いくつかの欠点:

  1. 向きの変更はサポートしていませんが、おそらく修正は簡単です。
  2. 他のlayoutManagersをサポートしていません。 LinearLayoutManagerのみ
  3. API 11以降が必要です。

コード:

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>

MainActivity

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

数日前にこの状況に出くわしたとき、私はこの質問につまずいた。 RecyclerViewのFastScrollの実装例

github.com/danoz73/RecyclerViewFastScroller

サンプルアプリケーションを実行してみて、コードを熟読して、単純なRecyclerViewFastScrollerウィジェットのかなり単純な使用法を確認してください。 githubには情報がありますが、ここでは垂直高速スクローラーの基本的な使用法を説明します。

完全な例については、 リポジトリ内のサンプルアプリケーション を参照してください。

基本的な使い方

RecyclerViewが存在するアクティビティまたはフラグメントXMLに、VerticalRecyclerViewFastScrollerオブジェクトを含めます。次の例は、相対的なレイアウトになります。

...
  <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"
    />
...

プログラムでレイアウトを設定するフラグメントまたはアクティビティで、高速スクローラーをリサイクラに接続します。

...
  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;
  }
...

お役に立てれば!

EDIT:Android-Lollipop-Contacts-styleセクションインジケーターのサポートが追加されました! サンプルアプリケーションの実装の詳細を確認してください。

52
Daniel Smith

RecyclerViewおよびfast-scroll/section indexerに関する未回答の質問が多数あります。ここで意見や情報を再グループ化して収集してみましょう。 。

短い答えは:いいえ、高速スクロールを有効にすることはできませんRecyclerView には FastScroller オブジェクトおよび関連する論理状態変数。これは、RecyclerViewAbsListView ではないためです。

一方、RecyclerViewのダンプバージョンと高速スクロールに必要なロジックを含むFastScrollerを実装することは不可能ではありませんが、これまでのところ実装は見ていません。

それについて、またはあなたが私が間違っていると思うなら、あなたの考慮を共有してください。

11
bonnyz

Android Support Library 26.0.0はfastScrollEnabledをサポートするようになりました

RecyclerViewの新しいfastScrollEnabledブール値フラグ。

有効にした場合、fastScrollHorizo​​ntalThumbDrawable、fastScrollHorizo​​ntalTrackDrawable、fastScrollVerticalThumbDrawable、およびfastScrollVerticalTrackDrawableを設定する必要があります。

サンプル- https://Android.jlelse.eu/fast-scrolling-with-recyclerview-2b89d4574688

10

RecyclerViewにはA-Z Fastscrollも使用できます。 iOSスタイルです。

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

それを使用する方法:

  • Android.support.v7.widget.RecyclerViewcom.codecomputerlove.fastscrollrecyclerviewdemo.FastScrollRecyclerViewに置き換えます
  • アダプターはFastScrollRecyclerViewInterfaceを実装し、getMapIndex()をオーバーライドする必要があります。関数はmapIndexを返す必要があります。 calculateIndexesForName()を調べて、作成方法のヒントを得てください。作成したら、コンストラクタでアダプタに渡します。
  • FastScrollRecyclerViewItemDecorationのインスタンスを作成し、RecyclerView FastScrollRecyclerViewItemDecoration decoration = new FastScrollRecyclerViewItemDecoration(this); mRecyclerView.addItemDecoration(decoration);に追加します
  • <dimen name="fast_scroll_overlay_text_size">100dp</dimen>/values/dimens.xmlファイルに追加します。これは、オーバーレイされた文字のdpサイズです
4
Flavius Mester

FastScroller機能は、RecyclerViewのAndroidライブラリ26.0.0から追加されます

コンパイルの依存関係

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

project.gradleに依存関係を追加します

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

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>
3
Abhishek Garg

Lib: https://github.com/FutureMind/recycler-fast-scroll を試すことができます。まだ初期の開発段階ですが、他のライブラリで経験したスムーズさの問題に対処するために特別に構築されました。少し異なるメカニズムを使用します。水平LayoutManagerもサポートし、近い将来、複数列のセットアップもサポートします。

編集:いくつかのきちんとしたカスタマイズオプションがあります。

3
Michał K

RecycleViewとそのLayoutManagerでスクロールバーを実装する規定があります。

たとえば、 computeVerticalScrollExtent()computeVerticalScrollOffset() および computeVerticalScrollRange() は、常に正しい位置に垂直スクロールつまみを配置するための情報を提供できます。

これらのメソッドは、実際の測定値を委任するための LayoutManager にもあります。したがって、使用されるLayoutManager実装はこれらの測定をサポートする必要があります。

また、スクロール変数のドラッグタッチは、RecyclerViewonInterceptTouchEvent() をオーバーライドすることでインターセプトできます。目的のスクロールを計算した後、 scrollTo() を呼び出してRecyclerViewを更新できます。

1
S.D.

高速スクロールを有効にして、次のようなスクロールバーのサム、トラッカーを追加するだけです。

<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
Maya Mohite