热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

RecyclerView首个Item滑到顶部渐变

RecyclerView首个Item顶部渐变效果抖音“新鲜”Tab页上有个效果比较有意思,当Item滑到顶部的时候,item上的文字信息会有一个渐变的隐藏效果,如下图这个效果实现起

RecyclerView 首个Item顶部渐变效果

抖音“新鲜”Tab页上有个效果比较有意思,当Item滑到顶部的时候,item上的文字信息会有一个渐变的隐藏效果,如下图

《RecyclerView首个Item滑到顶部渐变》

这个效果实现起来不是特别难,但是有一些细节地方需要我们考虑一下,下面我就把我实现的方式分享一下,先来一张效果图

《RecyclerView首个Item滑到顶部渐变》

实现方式

  • 使用RecyclerView.OnScrollListener监听RecyclerView的滚动
  • 在onScrolled(RecyclerView recyclerView, int dx, int dy)方法中获取第一个Item
  • 获取第一个Item的滑动出屏幕的百分比
  • 根据计算获取当前文字区域的Alpha值

代码如下:

RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
//这里我使用的是GridLayoutManager,并且RecyclerView只有两列
if(manager instanceof GridLayoutManager){
GridLayoutManager gridLayoutManager = (GridLayoutManager) manager;
int firstVisiblePos = gridLayoutManager.findFirstVisibleItemPosition();
setViewAplha(gridLayoutManager.findViewByPosition(firstVisiblePos));
setViewAplha(gridLayoutManager.findViewByPosition(firstVisiblePos+1));
int firstCompletelyVisible = gridLayoutManager.findFirstCompletelyVisibleItemPosition();
ItemView view1 = (ItemView) gridLayoutManager.findViewByPosition(firstCompletelyVisible);
ItemView view2 = (ItemView) gridLayoutManager.findViewByPosition(firstCompletelyVisible + 1);
if(view1 != null){
view1.setAlpha(1);
}
if(view2 != null){
view2.setAlpha(1);
}
}
}
};
float beginPercent = 0.2f;
float endValue = 2;
private void setViewAplha(View view){
if (view == null || !(view instanceof ItemView))
return;
float p = UIUtils.px2dip(Math.abs((int) view.getY())) * 1.0f / UIUtils.px2dip(view.getHeight()) * 1.0f;
float curPercent = Float.compare(p - beginPercent, 0.0f) <0 ? 0.0f : p - beginPercent;
curPercent = Float.compare(1, curPercent * endValue) <0 ? 1 : curPercent * endValue;
view.setAlpha(1 - curPercent);
}

这里的ItemView是自定义的每一个内容区域的View,布局比较简单 只有一个TextView 代码如下

private static class ItemView extends LinearLayout{
TextView textView;
Context mContext;
public ItemView(Context context) {
super(context);
mCOntext= context;
init();
}
private void init(){
View root = LayoutInflater.from(mContext).inflate(R.layout.layout_test_item,this);
textView = (TextView) root.findViewById(R.id.item_text);
}
public void setText(String text){
textView.setText(text);
}
public void setAlpha(float alpha){
textView.setAlpha(alpha);
}
}

需要考虑的细节问题

  • Adapter Holder的复用
    我们都知道RecyclerView.Adapter会对Holder进行复用来节约内存的开销,如果假设一屏有十个item,当我们滑动到第十一个Item时会复用第一个Item的Holder,所以在onBindViewHolder方法中我们需要把文字区域的Alpha值设置为不透明,adaper的代码如下:

RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ItemView itemView = new ItemView(parent.getContext());
ViewHolder holder = new ViewHolder(itemView);
return holder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ViewHolder holder1 = (ViewHolder) holder;
holder1.itemView.setText("我是Item"+position);
//需要把item设置不透明,否则可能会因为复用导致item刚显示就是看不见的
holder1.itemView.setAlpha(1);
}
@Override
public int getItemCount() {
return 40;
}
class ViewHolder extends RecyclerView.ViewHolder{
ItemView itemView;
public ViewHolder(View itemView) {
super(itemView);
this.itemView = (ItemView) itemView;
}
}
};

  • 快速滑动的问题
    RecyclerView 滑动时会有如下三种状态

/**
* The RecyclerView is not currently scrolling.
* @see #getScrollState()
*/
public static final int SCROLL_STATE_IDLE = 0;
/**
* The RecyclerView is currently being dragged by outside input such as user touch input.
* @see #getScrollState()
*/
public static final int SCROLL_STATE_DRAGGING = 1;
/**
* The RecyclerView is currently animating to a final position while not under
* outside control.
* @see #getScrollState()
*/
public static final int SCROLL_STATE_SETTLING = 2;

当我们快速滑动时可能会由于滑动速度过快,导致在下次回调时可能已经是下一个item元素,例如,在当前onScrolled方法回调时,findFirstVisibleItemPosition可能是item4,然后我们计算出文字区域的Alpha是0.6,因为滑动过快,下次回调onScrolled方法时,findFirstVisibleItemPosition可能就变成了item6,Alpha值是0.8,因为我们缺少了item4的完整状态,就导致了当快速滑动停止时,可能item6是正确的透明度,但是我们希望item4是完全不透明的,但是实际却是0.6
为了解决这个问题,我尝试了几种方法,像监听滑动状态啊、判断onScrolled中的dy参数啊,后来我发现我有点给想的麻烦了,其实不管滑动速度多快,每个item在滑动到第一个完全可展示的位置时,是一定会被我们知道的,比如虽然我们不能拿到item4从完全透明到完全不透明的所有状态,但是当item6是第一个item时,item4一定是第一可以完全展示的item(我的RecyclerView有两列),所以我们就可以通过这个点来下手,通过LayoutManager的findFirstCompletelyVisibleItemPosition来找到第一个完全可见的Item位置,具体体现就是刚才RecyclerView.OnScrollListener 里面的代码

int firstCompletelyVisible = gridLayoutManager.findFirstCompletelyVisibleItemPosition();
ItemView view1 = (ItemView) gridLayoutManager.findViewByPosition(firstCompletelyVisible);
ItemView view2 = (ItemView) gridLayoutManager.findViewByPosition(firstCompletelyVisible + 1);
if(view1 != null){
view1.setAlpha(1);
}
if(view2 != null){
view2.setAlpha(1);
}

  • Alpha值的计算
    这里还有一个要考虑的问题,就是Alpha的取值问题,仔细看抖音中的效果,并不是item刚开始滑动就开始改变透明度,而是大概Item滑出屏幕1/5左右开始,这里就需要我们做一点点小小的计算,当然我的计算方法可能有点low,计算方法就是刚才的setViewAplha里面所做的,在这在粘贴一下

float beginPercent = 0.2f;
float endValue = 2;
private void setViewAplha(View view){
if (view == null || !(view instanceof ItemView))
return;
float p = UIUtils.px2dip(Math.abs((int) view.getY())) * 1.0f / UIUtils.px2dip(view.getHeight()) * 1.0f;
float curPercent = Float.compare(p - beginPercent, 0.0f) <0 ? 0.0f : p - beginPercent;
curPercent = Float.compare(1, curPercent * endValue) <0 ? 1 : curPercent * endValue;
view.setAlpha(1 - curPercent);
}

这个beginPercent变量表示我想要在Item滑出屏幕多少时,才开始改变Alpha值,这里我定义成了0.2也就是1/5,然后在第一次计算curPercent时

float p = UIUtils.px2dip(Math.abs((int) view.getY())) * 1.0f / UIUtils.px2dip(view.getHeight()) * 1.0f;
float curPercent = Float.compare(p - beginPercent, 0.0f) <0 ? 0.0f : p - beginPercent;

可见如果当p<0.2时,我的curPercent会等于0,后续在做什么计算都不会改变文字区域的Alpha值
现在已经可以设置从item滑动到多少才开始出现渐变的效果了,那么下一步我们就应该定义当item滑动到什么位置时文字区域完全透明也就是Alpha值等于0,这时候endValue的作用就来了,我们可以通过给curPercent乘一个值来让它达到指定位置时可以变成1,然后1-curPercent=0

curPercent = Float.compare(1, curPercent * endValue) <0 ? 1 : curPercent * endValue;

这里我的endValue=2,可以在item滑出屏幕70%时,文字区域完全透明,我的计算方法如下表格

curPercent与0.2的差值(滑动从1/5开始计算)
0.0&#8211;
0.1&#8211;
0.2&#8211;
0.30.1
0.40.2
0.50.3
0.60.4
0.70.5
0.80.6
0.90.7

所以如果我想让Item滑动到70%时完全透明,我只要设置endValue是2既可,因为此时curPercent是0.7-0.2=0.5 然后乘2刚好等于1,之前一直都会小于1,这样的话,我们可以随意设定滑动渐变从哪开始到哪结束,比如我现在希望item滑出屏幕30%开始 同样在item滑出屏幕70%完全透明那么根据下面这个表格

curPercent与0.3的差值(滑动从30%开始计算)
0.0&#8211;
0.1&#8211;
0.2&#8211;
0.3&#8211;
0.40.1
0.50.2
0.60.3
0.70.4
0.80.5
0.90.6

我们可以计算出 endValue=3( (0.7-0.3)* endValue =1.2 )即可保证在滑动到70%时 完全的透明

ok 到这我们就可以完美表现出这种渐变的效果了,这是我第一次写简书,写的还有点小激动呢。欢迎所有读过的人 批评指正~


推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • 如何用Matlab快速画出带有3D渲染效果的复杂曲面
    简要地介绍了一下如何用Matlab快速画出带有3D渲染效果的复杂曲面图,包括三维曲面绘制、光线、材质、着色等等控制,以及如何 ... [详细]
  • 本文实例讲述了Android编程实现读取工程中的txt文件功能。分享给大家供大家参考,具体如下:1.众所周知,Android的res文件夹 ... [详细]
  • Android程序员面试宝典自定义控件一分钟实现贴纸功能一分钟实现TextView高亮一分钟实现新手引导页一分钟实现ViewPager卡片一分钟实现加载对话框一分钟实现轮播图一分钟 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • MPLS VP恩 后门链路shamlink实验及配置步骤
    本文介绍了MPLS VP恩 后门链路shamlink的实验步骤及配置过程,包括拓扑、CE1、PE1、P1、P2、PE2和CE2的配置。详细讲解了shamlink实验的目的和操作步骤,帮助读者理解和实践该技术。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 涉及的知识点-ViewGroup的测量与布局-View的测量与布局-滑动冲突的处理-VelocityTracker滑动速率跟踪-Scroller实现弹性滑动-屏幕宽高的获取等实现步 ... [详细]
  • 【clientX,offsetX,screenX】  【scrollWidth,clientWidth,offsetWidth】的区别
    一、深刻认识clientX,offsetX,screenX概念(来源于网络):clientX设置或获取鼠标指针 ... [详细]
author-avatar
Amyjionydp
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有