带有折叠工具栏的 RecyclerView 中的 Android 字母快速滚动视图
Posted
技术标签:
【中文标题】带有折叠工具栏的 RecyclerView 中的 Android 字母快速滚动视图【英文标题】:Android alphabetical fast scrollview in RecyclerView with Collapsing toolbar 【发布时间】:2016-11-25 06:11:55 【问题描述】:在我的应用程序中,我有这样的 activity_main.xml:-
<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_
android:layout_
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_
android:layout_
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_
android:layout_
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_
android:layout_
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_
android:layout_
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_
android:layout_
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
android:background="@drawable/theme_background"
app:layout_collapseMode="pin" >
<Spinner
android:id="@+id/spinner_nav"
android:layout_
android:layout_
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_
android:layout_
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
<ListView
android:layout_
android:layout_
android:id="@+id/navlist"
android:background="#dedede"
android:layout_gravity="start" />
</android.support.v4.widget.DrawerLayout>
现在我想在我的回收站视图中加入快速滚动功能,以便在滚动时弹出图像日期。
此类滚动条的示例图像:-
我搜索了这个并尝试使用几个库,但我认为由于我的折叠工具栏,滚动条无法正常工作。
使用的滚动库的屏幕截图:-
在我的例子中,滚动条从顶部开始,滚动计算也不正确。
请帮忙解决这个问题。
谢谢
【问题讨论】:
你看到了吗:***.com/questions/8192683/… 对不起,没有完整的xml代码我只能建议你搜索alphabetical scrollview
@piotrek1543 我为此使用了一些外部快速滚动库。但现在我想我需要自己创建滚动条。所以请告诉我如何开始
请xml布局文件;-)
@AnkeshkumarJaisansaria 如果你想使用这个库github.com/turing-tech/MaterialScrollBar/issues/20,也可以看到这个问题
【参考方案1】:
我们想要SectionIndexer
的一些知识。这是 SectionIndexer 的Doc。
我们必须设置为真 setFastScrollEnabled(true)
方法,该方法与LISTVIEW
一起使用......你可以使用recyclerview
代替listView
在下面的例子中......
这是活动
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));
);
这是 activity_fast_scoll.xml 文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:padding="5dp" >
<ListView
android:id="@android:id/list"
android:layout_
android:layout_
android:scrollbarStyle="outsideOverlay" />
</RelativeLayout>
这是我的自定义适配器,带有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;
这是 string.xml 文件中的水果数组。
<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>
最后这是这些代码的输出......
随时询问您是否卡在代码之间的任何地方......
注意:- FastScroll 图像在不同版本的 android(例如:-lollipop、marshmallow 等)中会有所不同,下面的输出是针对棒棒糖的
对于自定义字母快速滚动视图,只需将这两行添加到您的style.xml
文件中的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
自定义快速滚动输出:-
【讨论】:
setFastScrollEnabled 在 recyclerview 中不可用 @Nainal 上面带有 listView 的示例。 对于那些以编程方式面对recyclerview settign的人,通过xml设置它:`app:fastScrollEnabled="true"` 对于回收站视图检查这个:***.com/a/46026362/5664529【参考方案2】:有一个很好的库here 和这个example。还有一个很好的教程here,这个例子在Github。
用法:
制作一个实现 BubbleTextGetter 的 RecyclerView.Adapter,给定数据中的位置将返回文本以显示在气泡弹出窗口中。 将 FastScroller 放置在包含 RecyclerView 的布局内(可能位于右侧区域)。
自定义 FastScroller 的一些缺点:
不支持方向更改,但可能很容易修复。 不支持其他布局管理器。只有线性布局管理器 需要 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_
android:layout_>
<TextView
android:id="@+id/fastscroller_bubble"
android:layout_gravity="right|end"
android:gravity="center"
android:textSize="48sp" tools:text="A"
android:layout_
android:textColor="#FFffffff"
android:layout_
android:background="@drawable/recycler_view_fast_scroller__bubble"
android:visibility="visible"/>
<ImageView
android:id="@+id/fastscroller_handle"
android:layout_
android:layout_marginRight="8dp"
android:layout_marginLeft="8dp"
android:layout_
android:src="@drawable/recycler_view_fast_scroller__handle"/>
</merge>
现在这个 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);
这个自定义的线性布局:
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();
活动的最后一步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_
android:layout_
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_
android:layout_
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_
android:layout_
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_
android:layout_
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_
android:layout_
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_
android:layout_
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
android:background="@drawable/theme_background"
app:layout_collapseMode="pin" >
<Spinner
android:id="@+id/spinner_nav"
android:layout_
android:layout_
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_
android:layout_
android:background="@android:color/darker_gray" />
</android.support.design.widget.CoordinatorLayout>
</android.support.v4.widget.DrawerLayout>
【讨论】:
如何显示所选项目的文本 @AkashDubey 可以检查这个example in GitHub。【参考方案3】:要实现类似于电话联系人列表或与问题中给出的图像相同且具有文本和图像的图像,This 是我遇到的最佳解决方案!
这适用于自定义列表,因为图像可能需要与名称一起存在。以上解决方案只有String的列表或数组,可能不是每个人都需要!
只需 3 个简单步骤:
1.添加依赖implementation 'com.simplecityapps:recyclerview-fastscroll:2.0.1'
2.将您的RecyclerView
替换为com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
3. 在您的 recyclerview 适配器中实现 FastScrollRecyclerView.SectionedAdapter
完成了!
【讨论】:
以上是关于带有折叠工具栏的 RecyclerView 中的 Android 字母快速滚动视图的主要内容,如果未能解决你的问题,请参考以下文章
带有 RecyclerView 和折叠标题的 CoordinatorLayout
带有折叠工具栏的 RecyclerView 和 ViewPager
带有 MotionLayout 的 Android 折叠工具栏 - 当 RecyclerView 为空/不可滚动时禁用运动
RecyclerView 适合屏幕时不要折叠 Toolbar
NestedScrollViewLayout 内的 SwipeRefreshLayout 内的 RecyclerView 无法滚动