Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android alphabetical fast scrollview in RecyclerView with Collapsing toolbar

In my application I have activity_main.xml like this:-

<Coordinator Layout>    <AppBarLayout>       <CollapsingToolbarLayout>            <ImageView/>            <Toolbar/>        </CollapsingToolbarLayout>    </AppBarLayout>    <RecyclerView/> </Coordinating Layout> 

Layout.xml ----->>>

<?xml version="1.0" encoding="utf-8"?>    <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     xmlns:ads="http://schemas.android.com/apk/res-auto"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:background="@drawable/theme_background"     android:id="@+id/drawerlayout"     >       <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"         xmlns:app="http://schemas.android.com/apk/res-auto"         xmlns:tools="http://schemas.android.com/tools"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:fitsSystemWindows="true"         android:id="@+id/activity_main_id"         tools:context="objectdistance.ajai.ram.sita.gallery.MainActivity">          <android.support.design.widget.AppBarLayout             android:id="@+id/app_bar_layout"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:fitsSystemWindows="true"             android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">               <android.support.design.widget.CollapsingToolbarLayout                 android:id="@+id/collapsing_toolbar"                 android:layout_width="match_parent"                 android:layout_height="match_parent"                 app:layout_scrollFlags="scroll|exitUntilCollapsed"                 app:contentScrim="?attr/colorPrimary"                 app:expandedTitleMarginStart="48dp"                 app:expandedTitleMarginEnd="64dp"                 android:fitsSystemWindows="true">                    <ImageView                     android:id="@+id/imagetoolbar"                     android:layout_width="match_parent"                     android:layout_height="200dp"                     android:scaleType="centerCrop"                     android:fitsSystemWindows="true"                     android:foreground="@drawable/image_header_foreground"                     app:layout_scrollFlags="scroll"                     app:layout_collapseMode="parallax"/>                  <android.support.v7.widget.Toolbar                     android:id="@+id/toolbar"                     android:layout_width="match_parent"                     android:layout_height="?attr/actionBarSize"                     app:popupTheme="@style/ThemeOverlay.AppCompat.Light"                     android:background="@drawable/theme_background"                     app:layout_collapseMode="pin" >                      <Spinner                         android:id="@+id/spinner_nav"                         android:layout_width="wrap_content"                         android:layout_height="wrap_content"                          android:dropDownVerticalOffset="?attr/actionBarSize" />                  </android.support.v7.widget.Toolbar>              </android.support.design.widget.CollapsingToolbarLayout>           </android.support.design.widget.AppBarLayout>             <android.support.v7.widget.RecyclerView             android:id="@+id/list"             android:layout_width="match_parent"             android:layout_height="match_parent"             app:layout_behavior="@string/appbar_scrolling_view_behavior" />         </android.support.design.widget.CoordinatorLayout>       <ListView         android:layout_width="200dp"         android:layout_height="match_parent"         android:id="@+id/navlist"         android:background="#dedede"         android:layout_gravity="start" />  </android.support.v4.widget.DrawerLayout> 

Now I want to include fast scrolling to my recyclerview such that the image date can be popup on scrolling.

Sample image of such scrollbar:- Scrolling

I searched for this and tried using few libraries but I think due to my collapsing toolbar the scrollbar is not working properly.

Screenshot of scroll Library used:- My device

Here in my case the scroll bar is starting from top and the scroll computation is also not proper.

Please help solving this issue.

Thanks

like image 313
Ankesh kumar Jaisansaria Avatar asked Jul 21 '16 15:07

Ankesh kumar Jaisansaria


2 Answers

we want some Knowledge of SectionIndexer. Here is Doc of SectionIndexer.

We have to set TRUE setFastScrollEnabled(true) method, which is used with the LISTVIEW.......You can use recyclerview instead of listView in the below example....

this is activity

public class FastScoll extends ListActivity {      ListView fruitView;      @Override     public void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_fast_scoll);          fruitView = (ListView) findViewById(android.R.id.list);          fruitView.setFastScrollEnabled(true);         String[] fruits = getResources().getStringArray(R.array.fruits_array);          final List<String> fruitList = Arrays.asList(fruits);         Collections.sort(fruitList);         setListAdapter(new ListAdapter(this, fruitList));          fruitView.setOnItemClickListener(new AdapterView.OnItemClickListener() {              public void onItemClick(AdapterView<?> parent, View arg1,                                     int position, long arg3) {                 Log.e("sushildlh",fruitList.get(position));             }         });      } } 

this is the activity_fast_scoll.xml file

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:padding="5dp" >      <ListView         android:id="@android:id/list"         android:layout_width="fill_parent"         android:layout_height="fill_parent"         android:scrollbarStyle="outsideOverlay" />  </RelativeLayout> 

and this is my custom adapter with SectionIndexer....

public class ListAdapter extends ArrayAdapter<String> implements SectionIndexer {      String[] sections;     List<String> fruits;     List<String> sectionLetters=new ArrayList<String>();      public ListAdapter(Context context, List<String> fruitList) {         super(context, android.R.layout.simple_list_item_1, fruitList);         this.fruits = fruitList;          for (int x = 0; x < fruits.size(); x++) {             String fruit = fruits.get(x);             String ch = fruit.charAt(0)+"";             ch = ch.toUpperCase(Locale.US);              sectionLetters.add(ch);         }          ArrayList<String> sectionList = new ArrayList<String>(sectionLetters);          sections = new String[sectionList.size()];          sectionList.toArray(sections);     }      public int getPositionForSection(int section) {          Log.e("sushildlh", "" + section);         return section;     }      public int getSectionForPosition(int position) {          Log.d("sushildlh", "" + position);         return position;     }      public Object[] getSections() {         return sections;     } } 

this is fruits array in string.xml file.

 <string-array name="fruits_array">             <item>Apples</item>             <item>Apricots</item>             <item>Avocado</item>             <item>Annona</item>             <item>Banana</item>             <item>Bilberry</item>             <item>Blackberry</item>             <item>Custard Apple</item>             <item>Clementine</item>             <item>Cantalope</item>             <item>Coconut</item>             <item>Currant</item>             <item>Cherry</item>             <item>Cherimoya</item>             <item>Date</item>             <item>Damson</item>             <item>Durian</item>             <item>Elderberry</item>             <item>Fig</item>             <item>Feijoa</item>             <item>Grapefruit</item>             <item>Grape</item>             <item>Gooseberry</item>             <item>Guava</item>             <item>Honeydew melon</item>             <item>Huckleberry</item>             <item>Jackfruit</item>             <item>Juniper Berry</item>             <item>Jambul</item>             <item>Jujube</item>             <item>Kiwi</item>             <item>Kumquat</item>             <item>Lemons</item>             <item>Limes</item>             <item>Lychee</item>             <item>Mango</item>             <item>Mandarin</item>             <item>Mangostine</item>             <item>Nectaraine</item>             <item>Orange</item>             <item>Olive</item>             <item>Prunes</item>             <item>Pears</item>             <item>Plum</item>             <item>Pineapple</item>             <item>Peach</item>             <item>Papaya</item>             <item>Passionfruit</item>             <item>Pomegranate</item>             <item>Pomelo</item>             <item>Raspberries</item>             <item>Rock melon</item>             <item>Rambutan</item>             <item>Strawberries</item>             <item>Sweety</item>             <item>Salmonberry</item>             <item>Satsuma</item>             <item>Tangerines</item>             <item>Tomato</item>             <item>Ugli</item>             <item>Watermelon</item>             <item>Woodapple</item>         </string-array> 

and finally this is the output of the these code....

oo1o2

Feel free to ask if you stuck anywhere in between code ....

Note:- FastScroll image will be differ in different version of android (eg:-lollipop,marshmallow,etc) below output is for lollipop

lollipop

For Custom Alphabetical Fast scrollView just add these 2 line in your style.xml file in AppTheme.

<item name="android:fastScrollTextColor">@color/apptheme_color</item>         //this is used for the color of the Alphabetical Fast scrollView <item name="android:fastScrollPreviewBackgroundRight">@drawable/bg_default_focused_holo_light</item>          //this is the image or and drawable file you want to set on Alphabetical Fast scrollView 

Custom Fast Scorll Output :-

ouy

like image 187
sushildlh Avatar answered Oct 26 '22 20:10

sushildlh


There is a good library here with this example. Also there is a good tutorial here with this example in Github.

Usage:

make a RecyclerView.Adapter that implements BubbleTextGetter, which given a position in the data will return the text to show in the bubble-popup. position the FastScroller inside the layout that container the RecyclerView (probably at the right area).

Customize the FastScroller some disadvantages:

doesn't support orientation change, but it's probably easy to fix. doesn't support other layoutManagers. Only LinearLayoutManager Needs API 11 and above.

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> 

Now this ScrollListener:

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

This custom LinearLayout:

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

The last step in your activity onCreate:

    setContentView(R.layout.activity_main);     RecyclerView recyclerView =(RecyclerView)findViewById(R.id.activity_main_recyclerview);       FastScroller fastScroller=(FastScroller)findViewById(R.id.fastscroller);     fastScroller.setRecyclerView(recyclerView); 

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     xmlns:ads="http://schemas.android.com/apk/res-auto"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:background="@drawable/theme_background"     android:id="@+id/drawerlayout">      <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"         xmlns:app="http://schemas.android.com/apk/res-auto"         xmlns:tools="http://schemas.android.com/tools"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:fitsSystemWindows="true"         android:id="@+id/activity_main_id"         tools:context="objectdistance.ajai.ram.sita.gallery.MainActivity">          <android.support.design.widget.AppBarLayout             android:id="@+id/app_bar_layout"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:fitsSystemWindows="true"           android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">              <android.support.design.widget.CollapsingToolbarLayout                 android:id="@+id/collapsing_toolbar"                 android:layout_width="match_parent"                 android:layout_height="match_parent"                 app:layout_scrollFlags="scroll|exitUntilCollapsed"                 app:contentScrim="?attr/colorPrimary"                 app:expandedTitleMarginStart="48dp"                 app:expandedTitleMarginEnd="64dp"                 android:fitsSystemWindows="true">                  <ImageView                     android:id="@+id/imagetoolbar"                     android:layout_width="match_parent"                     android:layout_height="200dp"                     android:scaleType="centerCrop"                     android:fitsSystemWindows="true"                     android:foreground="@drawable/image_header_foreground"                     app:layout_scrollFlags="scroll"                     app:layout_collapseMode="parallax"/>                  <android.support.v7.widget.Toolbar                     android:id="@+id/toolbar"                     android:layout_width="match_parent"                     android:layout_height="?attr/actionBarSize"                     app:popupTheme="@style/ThemeOverlay.AppCompat.Light"                     android:background="@drawable/theme_background"                     app:layout_collapseMode="pin" >                      <Spinner                         android:id="@+id/spinner_nav"                         android:layout_width="wrap_content"                         android:layout_height="wrap_content"                         android:dropDownVerticalOffset="?attr/actionBarSize" />                  </android.support.v7.widget.Toolbar>              </android.support.design.widget.CollapsingToolbarLayout>          </android.support.design.widget.AppBarLayout>      <android.support.v7.widget.RecyclerView         android:id="@+id/activity_main_recyclerview"         android:layout_width="match_parent"         android:layout_height="@dimen/activity_main_height"         android:background="@android:color/darker_gray" />  </android.support.design.widget.CoordinatorLayout> </android.support.v4.widget.DrawerLayout> 
like image 35
Cabezas Avatar answered Oct 26 '22 20:10

Cabezas