Android轻松实现RecyclerView悬浮条

在我们在刷Instagram的动态时,你是否注意到这样一个小小的动效,就是当一条动态(以卡片形式呈现)向上滑动时,动态卡片的头部会始终悬浮在列表最上方,直到下一张动态卡片的头部将它顶掉并替换它悬浮着。言语可能说不清楚,就直接来看一下它的效果好了。

综合我上面的文字描述加上这张Gif图,我想大家应该知道这是个什么样的效果了吧。那么不废话了,接下来我就来说说一种很简单的实现方法吧。

思路

虽然实现起来炒鸡简单,但还是花了我一个多小时的时间思考实现。先说说思考过程吧,那天中午,Instagram给我推了一条消息(哈,就是我最喜欢的偶像金泰妍更新了Ins),于是我就点进去看了,喜欢了之后就开始研究这个效果,我反复地上下滑这个列表,因为Ins的列表有滚动条,我就发现每次滚动条在那个悬浮条附近的时候就会特别短。看到这个现象,敏锐的你是不是察觉到了什么?没错,我感觉这个就像是FrameLayout的效果,一个FrameLayout里按顺序有列表,悬浮条两个View,悬浮条覆盖在列表的上方,它在合适的时机更新自己的位置,在合适的时机更新自己的信息,然后看上去就像是一个悬浮的效果。

接下来我们思考的核心就转移到了如何确定并找到这个合适的时机。

再仔细观察上面的Gif图,我们可以确定当第二个列表项的头部距离列表顶端一个悬浮条的距离时,悬浮条随着列表的滑动改变自身的位置,从而看起来像是被顶掉的效果。画一张简单位置示意图

那么,数据更新的时机也很容易确定,就是在悬浮条恰好完全被顶掉的时候,更新自己的数据,并移动到列表顶部。

至于如何找到这个时机会在接下来的实现部分讲解。

实现

建立布局

如上面所言,就是一个简单的FrameLayout。


  1. <FrameLayout 
  2.     android:layout_width="match_parent" 
  3.     android:layout_height="match_parent" 
  4.     app:layout_behavior="@string/appbar_scrolling_view_behavior"> 
  5.  
  6.     <android.support.v7.widget.RecyclerView 
  7.         android:id="@+id/feed_list" 
  8.         android:layout_width="match_parent" 
  9.         android:layout_height="match_parent" 
  10.         android:background="@android:color/white" 
  11.         android:scrollbars="vertical" /> 
  12.  
  13.     <your-head-layout> 
  14.     …… 
  15.     </your-head-layout> 
  16. </FrameLayout>  

注意这里FrameLayout的第二个child应该为你列表项要悬浮显示的布局。

找到时机

根据我们的思路,我们首先要找到第二个列表项的头部距离列表顶端一个悬浮条的距离时的那个时机,如果我们能找到这个时机,那么第二个时机也相当于找出来了。

这里我们使用的是RecyclerView来实现列表,我们都知道RecyclerView的列表布局是由LayoutManager来确定的,由于一般要实现悬浮条显示效果的列表一般都为线性列表,即我们一般会使用LinearLayoutManager。通过LinearLayoutManager,我们可以很方便的获取到RecyclerView中相应位置的View,这里我们需要获取当前悬浮条数据来源的View和其下一个数据来源的View。这两个View有什么用呢?悬浮条显示的信息是来自第一个可见View的,而其下方的View正是第二个列表项,我们可以获取到它的top值。好了接下来就真的很简单了,我们只要给RecyclerView加一个ScrollListener,并在相应的回调里做之前我们想好的事就ok了,来看一下代码


  1. mFeedList.addOnScrollListener(new RecyclerView.OnScrollListener() { 
  2.     @Override 
  3.     public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 
  4.         super.onScrollStateChanged(recyclerView, newState); 
  5.         mSuspensionHeight = mSuspensionBar.getHeight(); 
  6.     } 
  7.  
  8.     @Override 
  9.     public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 
  10.         super.onScrolled(recyclerView, dx, dy); 
  11.         View view = linearLayoutManager.findViewByPosition(mCurrentPosition + 1); 
  12.         if (view != null) { 
  13.             if (view.getTop() <= mSuspensionHeight) { 
  14.                 mSuspensionBar.setY(-(mSuspensionHeight - view.getTop())); 
  15.             } else { 
  16.                 mSuspensionBar.setY(0); 
  17.             } 
  18.         } 
  19.  
  20.         if (mCurrentPosition != linearLayoutManager.findFirstVisibleItemPosition()) { 
  21.             mCurrentPosition = linearLayoutManager.findFirstVisibleItemPosition(); 
  22.             mSuspensionBar.setY(0); 
  23.  
  24.             updateSuspensionBar(); 
  25.         } 
  26.     } 
  27. });  

Tips:其中mCurrentPosition为悬浮条信息来自的那个列表项在RecyclerView的位置。还有这里的ScrollListener可以添加多个,在RecyclerView中会检查所有的ScrollListener并触发。

One more thing...

接下来,我们还需要……开玩笑,哪来的One more thing,我们已经完成了?什么?这么快?这么一点代码?恩,没错,就是只要这么一点代码就好了,我们来看一下最后我们实现的效果(当然最终效果的好坏还是取决与你列表项的布局,比如在Ins里这个效果就很好看呢~)

补充

上面这种情况我们RecyclerView的Item是单一的,但是我们的列表Item通常有很多种,只有在滑到我们想要类型的Item时才需要更新我们的悬浮条信息。比如很常见的通讯录,在我们滑到从A开头联系人滑到B开头联系人时,悬浮条的信息才从A变为B;再比如印象笔记的笔记列表,顶部的悬浮条是根据笔记的日期改变的。

那么,遇到这种情况我们应该怎么简单修改代码来实现我们需求呢?

其实很简单,思路已经由上面确定了,只是我们要让悬浮条移动的时机变化,变得更窄了,同时我们要更新的数据内容也发生了变化(这当然需要我们变换相应的布局)。


  1. mFeedList.addOnScrollListener(new RecyclerView.OnScrollListener() { 
  2.     @Override 
  3.     public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 
  4.         super.onScrollStateChanged(recyclerView, newState); 
  5.         mSuspensionHeight = mSuspensionBar.getHeight(); 
  6.     } 
  7.  
  8.     @Override 
  9.     public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 
  10.         super.onScrolled(recyclerView, dx, dy); 
  11.         //我们只是简单的收窄了我们让悬浮条移动的条件,这里就是ItemType必须对应时才发生移动 
  12.           if (adapter.getItemViewType(mCurrentPosition + 1) == MultiFeedAdapter.TYPE_TIME) { 
  13.             View view = linearLayoutManager.findViewByPosition(mCurrentPosition + 1); 
  14.             if (view != null) { 
  15.                 if (view.getTop() <= mSuspensionHeight) { 
  16.                     mSuspensionBar.setY(-(mSuspensionHeight - view.getTop())); 
  17.                 } else { 
  18.                     mSuspensionBar.setY(0); 
  19.                 } 
  20.             } 
  21.         } 
  22.  
  23.         if (mCurrentPosition != linearLayoutManager.findFirstVisibleItemPosition()) { 
  24.             mCurrentPosition = linearLayoutManager.findFirstVisibleItemPosition(); 
  25.             mSuspensionBar.setY(0); 
  26.  
  27.             updateSuspensionBar(); 
  28.         } 
  29.     } 
  30. });  

上面的代码我们只要注意注释处,其他的和之前给出的相同。

总之,虽然大家的需求可能不同,但万变不离其宗。只要掌握了思路,什么需求都不怕。

Github 上已增加相应代码,最后看一下我们的效果,只在时间变化时才移动悬浮条.

结语

哈哈,是不是很简单呢,最后再说一下封装的事,本来我是想封装一下的,由于每个人的列表布局都不一样,数据更新方式也不一样,就不封装了,是的,我水平不行,虽然我不想承认~不过代码真心特别少哦。希望这篇文章可以对你有帮助,我也会继续努力的。

作者:飞翔的荷兰豆

来源:51CTO

时间: 2025-01-26 17:50:30

Android轻松实现RecyclerView悬浮条的相关文章

Android 使用自定义RecyclerView控件实现Gallery效果

上篇文章给大家介绍了Android 自定义 HorizontalScrollView 打造多图片OOM 的横向滑动效果.其实制作横向滚动的不得不说另一个控件,就是Google官方最近新增加的RecyclerView,据说是ListView的升级版本,本篇文章,首先介绍RecyclerView的用法,然后经行一定的分析:最后自定义一下RecyclerView实现我们需要的相册效果. 1.RecyclerView的基本用法 首先主Activity的布局文件: <RelativeLayout xmln

求android大神! Android视频播放休眠后亮度条会改变

问题描述 求android大神! Android视频播放休眠后亮度条会改变 播放视频的时候,手动休眠,在唤醒的时候,本来默认的100%亮度只有70%了 解决方案 可能是系统自动处理的,你可以再次设置成亮度100 解决方案二: 这是Android系统自带的节电方案

Android 轻松实现语音识别

  苹果的iphone 有语音识别用的是Google 的技术,做为Google 力推的Android 自然会将其核心技术往Android 系统里面植入,并结合google 的云端技术将其发扬光大. 所以Google Voice Recognition在Android 的实现就变得极其轻松. 语音识别,借助于云端技术可以识别用户的语音输入,包括语音控制等技术,下面我们将利用Google 提供的Api 实现这一功能. 功能点为:通过用户语音将用户输入的语音识别出来,并打印在列表上. 功能界面如下:

ios制作悬浮条方法

有些应用会制作一些悬浮条,即在滚动到某个位置以上是,把某个区域悬浮在最顶上,当向下滚动到指定位置时,又自由地滚动着. 原理很简单. #pragma mark - UIScrollViewDelegate - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == _scrollView) { if (_scrollView.contentOffset.y >= 218) { _overView.hidden

Android 蓝牙 能否广播一条指令让多个蓝牙设备收到?

问题描述 Android 蓝牙 能否广播一条指令让多个蓝牙设备收到? 请教各位大神,蓝牙是否能广播一条指令让多个蓝牙设备收到? 我想通过手机通过控制多个蓝牙灯,如何处理?在线等. 解决方案 你可以构建一个蓝牙局域网来实现你的要求 http://blog.163.com/kjpt126%40126/blog/static/4894042620071112113059874/

android悬浮窗-android写了一个悬浮窗,但是输入法显示不出来了,希望能得到朋友们的帮助,谢谢了。

问题描述 android写了一个悬浮窗,但是输入法显示不出来了,希望能得到朋友们的帮助,谢谢了. 用android编写了悬浮窗,项目是用Unity3d做的,项目中的输入法软键盘无法显示了,能接收到按键,但是软键盘看不到. windowParams的参数如下,主要的问题在flags windowParams.type = LayoutParams.TYPE_PHONE; windowParams.format = PixelFormat.RGBA_8888; windowParams.flags

Android学习笔记(24):进度条组件ProgressBar及其子类

ProgressBar作为进度条组件使用,它还派生了SeekBar(拖动条)和RatingBar(星级评分条).   ProgressBar支持的XML属性: Attribute Name Related Method Description style   设置ProgressBar指定风格 android:indeterminate   设置为true时,进度条不显示进度 android:indeterminateBehavior   indeterminate模式下,当进度条达到最大值时的

Android 数据绑定之: RecyclerView

本文讲的是Android 数据绑定之: RecyclerView, 简化, 复用, 重新绑定 有时我会想,"数据绑定"这个名词并不一定特指 Android 中的数据绑定.RecyclerView 就有它独特的方法将其数据绑定到 UI 控件上.它有一个 Adapter,其中需要我们实现两个非常重要的方法来进行数据绑定: RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType); void onBi

Android中使用RecyclerView实现下拉刷新和上拉加载_Android

推荐阅读:使用RecyclerView添加Header和Footer的方法                       RecyclerView的使用之HelloWorld RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好.本文给大家介绍如何为RecyclerView添加下拉刷新和上拉加载,过去在ListView当中添加下拉刷新和上拉加载是非常方便的利用addHeaderView和addFooterVie