
问题:recyclerview在每个item里面都有一个chekcbox,如果我有20个item,我选中的第一个item的checkbox,那么下面一定会有一个item会跟第一个item进行复用,其实这不仅仅是checkbox,你换成一个图标也一样的道理,选中和不选中依然会有这个问题
解决思路:
1,能不能不让条目复用(违背了recyclerview的设计初衷,如果列表是固定的几条item可以用)
2,item选中状态是一种数据(true/false),能不能让数据不复用
所有的item状态都用一个map集合存起来,
在页面加载时候,在适配器的构造函数中需要对map集合进行初始化(所有的checkbox默认选中是false)
当你点击checkbox的时候,我们去重新设置checkbox的状态,然后获取,这样就能够完美的解决复用问题了
然后再回调这个map的数据
参考链接: >
获取RecyclerView滑动的距离。
Android教程2020 - 系列总览
前面我们已经用 RecyclerView显示一些数据
。
本文演示如何获取RecyclerView的滑动距离。
要实现这个功能,需要给RecyclerView添加滑动时监听 RecyclerViewOnScrollListener 。
RecyclerViewOnScrollListener 是一个抽象类,我们可以选择性地实现它的方法。
onScrolled 方法的 dy 表示的是每一次y方向上的相对滑动距离。向下滑动是正数,向上滑动是负数。
可以添加一个变量来累计滑动的距离。
每次滑动都累加到 mmRvScrollY 中。
打印log
建议同时给adapter加个 registerAdapterDataObserver ,监听插入/删除/移动,自己加减前面记录的dy滚动值。
工程放这里: >
在使用 RecyclerView 这个强大的滚动控件的时候,需要为它提供一个 Adapter 适配器,这个适配器继承自 RecyclerViewAdapter 这个类。
这个类里面有三个抽象方法需要我们去重写,分别是:
用于加载 RecyclerView 子项的布局,然后返回一个 ViewHolder 对象,ViewHolder 是一个静态内部类,继承自 RecyclerViewViewHolder 类。
为子项绑定数据。
调用这两个方法后,子项就既有了布局又有了数据。
用于获取 RecyclerView 一共有多少子项
MainActivityjava:
TextAdapterjava:
activity_mainxml:
text_itemxml:
我的博客即将同步至 OSCHINA 社区,这是我的 OSCHINA ID:ByLee,邀请大家一同入驻: >
1 利用OnScrollListener
[java] view plain copy
mRecyclerViewaddOnScrollListener(new RecyclerViewOnScrollListener() {
private int totalDy = 0;
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
totalDy -= dy;
}
});
如代码所述,totalDy的确保存了 RecyclerView 的滑动距离,但是当我向下滑动 RecyclerView ,之后插入/删除/移动 Item 的时候,totalDy 就变得不精确了;比如删除或者插入新的Item,那么totalDy就不能再回归到 0了。
1监听RecyclerView的addOnScrollListener后自己记录onScrolled的dy,同时给adapter加个registerAdapterDataObserver,监听插入/删除/移动,自己加减前面记录的dy滚动值。自己没有试过,不知道是否可行!
2 有人说可以尝试computeVerticalScrollOffset()
[java] view plain copy
totalDy = recyclerViewcomputeVerticalScrollOffset();
然而compute方法计算出的并不是滑动的精确距离,stackOverflow上有答案解释其为 item 的平均高度 可见 item 数目,不是我们需要的精确距离。
3 还有人说可以尝试getChildAt(0)
[java] view plain copy
totalDy = recyclerViewgetChildAt(0)getTop();
依靠第一个item的滑动距离来进行动画的设置,但是根据该方法得出的 totalDy 在滑动到一定程度后清零。
这是因为recyclerViewlgetChildAt(0) 返回的永远是第一个可见的child,不是所有view list 的第一个child,因此这种用法是得不到滑动距离的。
另外下面这三种用法都是等价的,都是获取第一个可见的child:
[java] view plain copy
LinearLayoutManager layoutManager = (LinearLayoutManager) thisgetLayoutManager();
View firstVisiableChildView = thisgetChildAt(0);
View firstVisiableChildView = layoutManagergetChildAt(0)
int position = layoutManagerfindFirstVisibleItemPosition();
View firstVisiableChildView = layoutManagergetChildAt(position)
但是下面这种就不是获取第一个可见的child,而是获得所有view list 的第一个child。但是滑动一段距离后它总是返回null,即第一个child被recycle后,总是返回null。
[java] view plain copy
//Don't use this function to get the first item, it will return null when the first item is recycled
LinearLayoutManager layoutManager = (LinearLayoutManager) thisgetLayoutManager();
View child2 = layoutManagerfindViewByPosition(0);
4如果LayoutManager用的是LinearLayoutManager,强烈推荐下面的方法获取滑动距离:
[java] view plain copy
public int getScollYDistance() {
LinearLayoutManager layoutManager = (LinearLayoutManager) thisgetLayoutManager();
int position = layoutManagerfindFirstVisibleItemPosition();
View firstVisiableChildView = layoutManagerfindViewByPosition(position);
int itemHeight = firstVisiableChildViewgetHeight();
return (position) itemHeight - firstVisiableChildViewgetTop();
}
LayoutManager是一个抽象类,有3个子类:
LinearLayoutManager : 线性布局管理器 GridLayoutManager : 表格布局管理器 StaggeredGridLayoutManager : 瀑布流布局管理器
LinearLayoutManager 是线性布局管理器,使用频率是最高的,展示的样式跟listview一模一样。 该类有3个构造方法:
第一个构造方法内部调用了第二个构造方法,第二个构造方法参数的含义:
orientation也可以通过mangersetOritation()设置 reverseLayout,也可以通过managersetReverseLayout()设置。 setStackFromEnd(boolean stackFromEnd) 当设置为true时,列表便会从底部开始展示内容,RecycelrView会自动滑倒尾部。 这个方法和managersetReverseLayout(true)共同点就是都自动滑动尾部,RecyclerView默认会展示末尾的item。差别在于,managersetStackFromEnd(true)不会影响内部的数据顺序,怎么添加进Adapter的,就怎么展示。
scrollToPosition(int position) 滑动到指定item linearLayoutManagerscrollToPositionWithOffset(int position,int offset) 滑动到指定item,在这个基础上,又附加偏移了offset的距离。
获取当前RecyclerView首尾可见item的位置方法
这4个方法,只有当RecyclerView在屏幕展示出来后,才能得到正常的返回值,否则都是-1
该管理器继承LinearLayoutManager,也有3个构造方法,由于是继承LiearLayoutMnager,使用起来差别不大,构造方法内使用了super()方法来直接调用了父类的构造方法:只是构造函数会多一个参数 spanCount : 列数 根据方法的注释,可以知道,默认情况下,GridLayoutManager是垂直的。在方法内,列数是调用setSpanCount(spanCount)进行设置。如果GridLayoutManager是水平的,则spanCount 代表行数,这个还是很容易理解。 GridLayoutManager不支持setStackFromEnd(),但支持setReverseLayout(boolean)方法。其他LinearLayoutManager的方法在上面已经提过了,就不重复了。
这里我们spanCount 设置为3,效果如下图
构造函数StaggeredGridLayoutManager(int spanCount, int orientation) 意思和GridLayoutManager一样。使用也是一样。这边就不具体表现讲了,看效果
使用这3个布局管理器,差不多90%的需求都能满足吧,LayoutManager也可以自定义实现,后面有用在进行详细讨论,这边仅说简单的使用。
git地址: >
Android深入理解RecyclerView的缓存机制
RecyclerView在项目中的使用已经很普遍了,可以说是项目中最高频使用的一个控件了。除了布局灵活性、丰富的动画,RecyclerView还有优秀的缓存机制,本文尝试通过源码深入了解一下RecyclerView中的缓存机制。
RecyclerView做性能优化要说复杂也复杂,比如说布局优化,缓存,预加载等等。其优化的点很多,在这些看似独立的点之间,其实存在一个枢纽:Adapter。因为所有的ViewHolder的创建和内容的绑定都需要经过Adaper的两个函数onCreateViewHolder和onBindViewHolder。
因此我们性能优化的本质就是要减少这两个函数的调用时间和调用的次数。如果我们想对RecyclerView做性能优化,必须清楚的了解到我们的每一步 *** 作背后,onCreateViewHolder和onBindViewHolder调用了多少次。因此,了解RecyclerView的缓存机制是RecyclerView性能优化的基础。
为了理解缓存的应用场景,本文首先会简单介绍一下RecyclerView的绘制原理,然后再分析其缓存实现原理。
RecyclerView滑动时会触发onTouchEvent#onMove,回收及复用ViewHolder在这里就会开始。我们知道设置RecyclerView时需要设置LayoutManager,LayoutManager负责RecyclerView的布局,包含对ItemView的获取与复用。以LinearLayoutManager为例,当RecyclerView重新布局时会依次执行下面几个方法:
上述的整个调用链:onLayoutChildren()->fill()->layoutChunk()->next()->getViewForPosition(),getViewForPosition()即是是从RecyclerView的回收机制实现类Recycler中获取合适的View,下面主要就来从看这个Recycler#getViewForPosition()的实现。
上述逻辑用流程图表示:
RecyclerView在Recyler里面实现ViewHolder的缓存,Recycler里面的实现缓存的主要包含以下5个对象:
public final class Recycler {
final ArrayList mAttachedScrap = new ArrayList<>();
ArrayList mChangedScrap = null;
RecyclerView在设计的时候讲上述5个缓存对象分为了3级。每次创建ViewHolder的时候,会按照优先级依次查询缓存创建ViewHolder。每次讲ViewHolder缓存到Recycler缓存的时候,也会按照优先级依次缓存进去。三级缓存分别是:
使用自定义ViewCacheExtension后,view离屏后再回来不会走onBindViewHolder()方法。
holdersetIsRecyclable(false),这样的话每次都会走onCreateViewHolder()和onBindViewHolder()方法
1提前初始化viewHolder,放到缓存池中
viewPoolputRecycledView(adapteronCreateViewHolder(recyclerView, 1))
2提前初始化view,在onCreateViewHolder的时候去取view
3自定义ViewCacheExtension
4适当的增加cacheSize
4公用缓存池,比如多个viewPager+fragment场景使用,或者全局单利缓存池,感觉用户不大。
有2中做法有值
第一种
第二种
不会,因为prefetch(GapWorker中的一个方法)之后mViewCacheMax会变成mRequestedCacheMax + extraCache
有2种方式可以让缓存失效
第一种
recyclerViewsetItemViewCacheSize(-1)
第二种
recyclerViewsetItemViewCacheSize(0)
layoutManagerisItemPrefetchEnabled = false
设置不缓存后,来回滑动让view进入屏幕离开屏幕,viewHolder的item时会多次走onBindViewHolder()方法。
在数据集发生变化后调用了Adapter的notifyDataSetChanged的onChanged函数后,就会调用观察者的onChanged函数,然后调用requestLayout方法重新布局。
在方法调用链中,requestLayout()→onLayout()→dispatchLayout()→onLayoutChildren()。
在LinearLayoutManager中,重写了onLayoutChildren(),在onLayoutChildren函数中会调用fill函数,在fill函数中会调用layoutChunk函数。
在Recycler中获取ItemView步骤如下,
1从mChangedScrap中获取ViewHolder缓存,
2从mAttachedScrap中获取ViewHolder缓存
3没有ViewHolder函数,会调用onCreateViewHolder函数,
4绑定数据,则调用Adapter的onBindViewHolder
总结: Recyclew通过适配器模式和观察者模式,进行数据绑定,
Adapter封装了ViewHolder的创建和绑定,而将布局工作交给了LayoutManager,在LayoutManager中进行ItemView的布局。
以上就是关于Checkbox的RecyclerView单选,多选问题全部的内容,包括:Checkbox的RecyclerView单选,多选问题、如何实现让RecyclerView有不同尺寸的item、Android教程2020 - RecyclerView获取滑动距离等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)