1.å¦ä½ä½¿ç¨RecyclerView
2.如何高效、源码简单实现菜单拖拽排序?
3.Android--RecyclerView嵌套RecyclerView优化
4.Android RecyclerView使用简述
5.RecyclerView详解
å¦ä½ä½¿ç¨RecyclerView
1ãæå¼SDK Managerï¼å¨Extrasæ ä¸æ¾å°Android Support Libraryï¼ä¸è½½å¥½æ¯æå ãRecyclerViewå¨v7-çæ¬å°±åºæ¥äºãæè¿éä¸ç¨æ´æ°äºï¼è¯´ææ¯ææ°çï¼æä¹å¯è½ä¸è¡å¢ç
2ãæ£æ¥appçbuild.gradleãéé¢ççv7çæ¬ä¹é½æ¯.2.1
3ãæå¼External Librariesï¼ç´æ¥æ¾å°ç±»ï¼ä¹æ²¡æ
4ãæ¥çappcompat-v7-.2.1çå±æ§ï¼éé¢ææºä»£ç å¼ç¨çä½ç½®ï¼å¨SDKç®å½ä¸ï¼\extras\android
\m2repository\com\android\support\appcompat-v7\.2.1\appcompat-v7-.2.1-sources.jar
5ãæå¼ä¸é¢ç®å½åï¼åç°éé¢æappcompat-v7ï¼èä¸éé¢ææ°çæ¬å°±æ¯.2.1
6ãæç §ç¬¬2æ¥çæè·¯ï¼è¯è¯ç´æ¥ç¼è¯è¿æ¥æ¯å¦OKãæç §ç®å½ç»æï¼å¨appçbuild.gradleçdependenciesæåæ·»å äºä¸å¥ï¼
compile âcom.android.support:recyclerview-v7:.2.1â
7ãBuildââClean Projectãçå¾ Cleanå®æ¯åï¼å¨External Librariesä¸çå°äºæå¾ ä¸çrecyclerview
8ãè½å¯¼å ¥å äºã
å¨\extras\android\support\v7\recyclerview\libs ç®å½ä¸åç°æandroid-support-v7-recyclerview.jarãè¦æ¯ä¸é¢çæ¹æ³ä¸è¡ï¼è¿å°±æ¯ç¬¬äºç§è§£å³åæ³äºï¼ç´æ¥å¯¼å ¥å°libsä¸äº
如何高效、源码简单实现菜单拖拽排序?
本文主角是源码ItemTouchHelper,它是源码RecyclerView对于item交互处理的一个辅助类,主要用于拖拽以及滑动处理。源码通过接口实现的源码识别拍照源码方式,达到配置简单、源码逻辑解耦、源码职责分明的源码效果,并且支持所有的源码布局方式。实现主要包含自定义一个类,源码实现ItemTouchHelper.Callback接口,源码并在实现方法中根据需求简单配置。源码接口包含三个必须实现的源码方法:getMovementFlags、onMove和onSwiped。源码getMovementFlags用于创建交互方式,交互方式分为两种,进度条源码最后通过makeMovementFlags把结果返回回去,makeMovementFlags接收两个参数,dragFlags和swipeFlags,即上面拖拽和滑动组合的标志位。onMove方法在拖拽时回调,这里主要对起始位置和目标位置的item做一个数据交换,然后刷新视图显示。onSwiped方法在滑动时回调,这个回调方法里主要是做数据和视图的更新操作。
接下来就是把这个辅助类绑定到RecyclerView。上面接口实现部分我们已经简单写好了,逻辑也挺简单,总共不超过行代码。绑定只需要调用attachToRecyclerView就好了。至此,简单的零点源码效果就已经实现了。下面开始优化和进阶的部分。
为了优化,我们添加了设置分割线的功能。RecyclerView网格布局实现等分,我们一般先是自定义ItemDecoration,然后调用addItemDecoration来实现的。但是我在实现效果的时候遇到一个问题,因为我加了布局切换的功能,在每次切换的时候,针对不同的布局分别设置layoutManager和ItemDecoration,这就导致随着切换次数的增加,item的间隔就越大。addItemDecoration,顾名思义是添加,通过查看源码发现RecyclerView内部是有一个ArrayList来维护的,所以当我们重复调用addItemDecoration方法时,万词霸屏源码分割线是以递增的方式在增加的,并且在绘制的时候会从集合中遍历所有的分割线绘制。部分源码显示了这一过程。
既然知道了问题所在,也大概想到了3种解决办法:1.调用addItemDecoration前,先调用removeItemDecoration方法remove掉之前所有的分割线;2.调用addItemDecoration(@NonNull ItemDecoration decor, int index),通过index来维护。实际上并不太行...因为始终都有两个分割线实例。我们再来梳理一下:我想到另外一个办法,不对RecyclerView做处理了,既然两种布局都有分割线,是不是可以把分割线合二为一了,然后根据LayoutManager去绘制不同的分割线?理论上是可行的,事实上也确实可以...自定义分割线:
为了提升用户体验,我们添加了选中放大/背景变色的功能。这里用到ItemTouchHelper.Callback中的在线报名系统 源码两个方法,onSelectedChanged和clearView。我们需要在选中时改变视图显示,结束时再恢复。onSelectedChanged方法在拖拽或滑动发生改变时回调,这时我们可以修改item的视图。clearView方法在拖拽或滑动结束时回调,这时我们要把改变后的item视图恢复到初始状态。
在实际需求中,我们可能还需要实现固定位置的功能。定义一个固定值,并设置不同的背景色和其他菜单区分开。在onMove方法中判断,只要是固定位置就直接返回false。虽然第一个菜单无法交换位置了,但是它还是可以拖拽的。为了进一步提升用户体验,我们可以让固定位置不可以拖拽。ItemTouchHelper.Callback中有两个方法可以实现这一点:这俩方法默认都是true,所以即使不能交换位置,但默认也是支持操作的。我们可以通过重写isLongPressDragEnabled方法把它禁掉,然后再非固定位置的时候去手动开启。
在进行拖拽操作时,下标其实是变化的,在做相应的操作时,要取实时位置。不管是拖拽还是滑动,其实本质都是对Adapter内已填充的数据进行操作,实时数据通过Adapter获取即可。如果想要实现重置功能,直接拿最开始的原始数据重新塞给Adapter即可。
在看源码时,找对一个切入点,往往能达到事半功倍的效果。这里就从绑定RecyclerView开始吧。实例化ItemTouchHelper,然后调用其attachToRecyclerView方法绑定到RecyclerView。在这一过程中,代码其实有点意思的,解读一下:关键点在于通过触摸和手势识别来处理交互显示。通过MotionEvent来判断并调用相应的回调方法,如select、checkSelectForSwipe和moveIfNecessary,最终通过invalidate()方法实时刷新界面。
总结源码,本质工作都是由源码帮我们做了,我们只需要在回调里根据结果处理业务逻辑即可。通过上述步骤,我们可以实现高效的菜单拖拽排序功能,提升用户体验。
Android--RecyclerView嵌套RecyclerView优化
使用RecyclerView嵌套RecyclerView时,用户常常会遇到操作不流畅、卡顿的问题。
在RecyclerView的源码中,onInterceptTouchEvent方法负责处理事件。特别是MOVE事件,RecyclerView仅进行了距离判断,当滑动距离超过系统默认阈值时,RecyclerView会自行滑动。这就解释了为什么在水平滑动时,子RecyclerView无法接收到Touch事件。为了解决这个问题,我们修改了拦截方法,只有在水平滑动距离大于竖直滑动距离时,RecyclerView才拦截事件。
然而,在子RecyclerView快速滑动且尚未停止时,如果我们尝试竖直滑动,会发现父RecyclerView无法接收到Touch事件。为了解决这个问题,我们找到了requestDisallowInterceptTouchEvent方法并进行了修改。
以下是相关视频和资源:
Android进阶开发:RecyclerView 内存管理与设计思想讲解
Android RecyclerView使用简述
Android中的RecyclerView是一个功能强大且灵活的视图组件,它能够展示一系列的数据项。与传统的ListView相比,RecyclerView具有更高的性能和更多的灵活性。使用RecyclerView时,需要创建一个Adapter来管理数据和视图,这里的Adapter与ListView的Adapter相似。同时,还需要创建一个LayoutManager来管理RecyclerView中子视图的排列方式,并实现滚动效果。除此之外,RecyclerView还支持添加和移除子视图,以及支持添加和移除动画效果等功能。
提供包括软件源代码、软件需求规格说明书、软件设计报告、软件测试报告、软件用户手册在内的相关文档。
以下是使用RecyclerView的几个简单步骤:
1. 在build.gradle文件中添加RecyclerView的依赖库:
implementation 'androidx.recyclerview:recyclerview:1.1.0'
2. 在布局文件中添加RecyclerView组件:
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
3. 创建RecyclerView的Adapter:
public class MyAdapter extends RecyclerView.Adapter {
private List mData; //数据源
//自定义ViewHolder,用于管理子视图的View对象
static class ViewHolder extends RecyclerView.ViewHolder {
TextView title;
ViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
}
}
//构造方法,传入数据源
public MyAdapter(List data) {
mData = data;
}
//创建ViewHolder对象并返回
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
//绑定数据到ViewHolder中的View对象
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.title.setText(mData.get(position));
}
//返回数据源的长度
@Override
public int getItemCount() {
return mData.size();
}
}
4. 创建RecyclerView的LayoutManager:
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
5. 设置Adapter:
MyAdapter adapter = new MyAdapter(dataList);
recyclerView.setAdapter(adapter);
RecyclerView详解
RecyclerViewä½ä¸ºListViewåGridViewçæ¿ä»£ï¼ä½æ¯åListViewä¸ä¸æ ·çæ¯ï¼RecyclerViewä¸åè´è´£Itemçææ¾çæ¾ç¤ºæ¹é¢çåè½ï¼ææåå¸å±ãç»å¶çæ¹é¢çå·¥ä½é½æåæä¸åçç±»è¿è¡ç®¡çã
RecyclerViewä¸ListViewçä¸åç¹ï¼ä¸»è¦å¨äºä»¥ä¸å 个ç¹æ§ï¼
å¦æä½ æ³ä½¿ç¨RecyclerViewï¼éè¦å以ä¸æä½ï¼
æ们å¯ä»¥ä»ä¸å¾æ´ç´è§çäºè§£å°RecyclerViewçåºæ¬ç»æï¼
RecyclerViewä¸åè´è´£Itemè§å¾çå¸å±åæ¾ç¤ºï¼æ以RecyclerViewä¹æ²¡æ为Itemå¼æ¾OnItemClickçç¹å»äºä»¶ãå¯ä»¥éè¿ä»¥ä¸æ¹å¼è¿è¡ï¼å 为å¨ViewHolderæ们å¯ä»¥æ¿å°æ¯ä¸ªItemçæ ¹å¸å±ï¼æ以å¦ææä»¬ä¸ºæ ¹å¸å±è®¾ç½®åç¬çOnClickçå¬å¹¶å°å ¶å¼æ¾ç»Adapterï¼é£ä¹å°±å¯ä»¥å¨ç»è£ RecyclerViewæ¶å°±è½å¤è®¾ç½®ItemClickListenerï¼åªä¸è¿è¿ä¸ªListenerä¸æ¯è®¾ç½®å°RecyclerViewä¸èæ¯è®¾ç½®å°Adapterã
å¤Itemå¸å±ï¼getItemViewTypeæ¹æ³ï¼ç¨æ³åListView没æä»»ä½åºå«ï¼è¿éè¦æ³¨æçæ¯å½æ°onCreateViewHolder(ViewGroup parent, int viewType)ç第äºä¸ªåæ°å°±æ¯Viewçç±»åï¼å¯ä»¥æ ¹æ®è¿ä¸ªç±»åå¤æå»å建ä¸åitemçViewHolderï¼ä»èå®æå¤Itemå¸å±ã
å¨RecylerViewä¸ï¼Adapteræ®æ¼ç两个è§è²ï¼ä¸æ¯æ ¹æ®ä¸åviewTypeå建ä¸ä¹ç¸åºççitemViewï¼äºæ¯è®¿é®æ°æ®éå并å°æ°æ®ç»å®å°æ£ç¡®çViewä¸ãè¿å°±éè¦æ们å®ç°ä»¥ä¸ä¸¤ä¸ªå½æ°ï¼
å¦å¤æ们è¿éè¦éåå¦ä¸ä¸ªæ¹æ³ï¼åListView-Adapteré£æ ·ï¼åæ ·å°åè¯RecyclerView-Adapterå表Itemsçæ»æ°ï¼
ViewHolderæè¿°RecylerViewä¸æ个ä½ç½®çitemViewåå æ°æ®ä¿¡æ¯ï¼å±äºAdapterçä¸é¨åï¼å ¶å®ç°ç±»é常ç¨äºä¿åfindViewByIdçç»æã 主è¦å ç´ ç»ææï¼
å ³äºViewHolderï¼è¿é主è¦ä»ç»mFlagsï¼
FLAG_BOUNDââViewHolderå·²ç»ç»å®å°æ个ä½ç½®ï¼mPositionãmItemIdãmItemViewTypeé½ææ
FLAG_UPDATEââViewHolderç»å®çView对åºçæ°æ®è¿æ¶éè¦éæ°ç»å®ï¼mPositionãmItemIdè¿æ¯ä¸è´ç
FLAG_INVALIDââViewHolderç»å®çView对åºçæ°æ®æ æï¼éè¦å®å ¨éæ°ç»å®ä¸åçæ°æ®
FLAG_REMOVEDââViewHolder对åºçæ°æ®å·²ç»ä»æ°æ®é移é¤
FLAG_NOT_RECYCLABLEââViewHolderä¸è½å¤ç¨
FLAG_RETURNED_FROM_SCRAPââè¿ä¸ªç¶æçViewHolderä¼å å°scrap list被å¤ç¨ã
FLAG_CHANGEDââViewHolderå 容åçååï¼é常ç¨äºè¡¨ææItemAnimatorå¨ç»
FLAG_IGNOREââViewHolderå®å ¨ç±LayoutManager管çï¼ä¸è½å¤ç¨
FLAG_TMP_DETACHEDââViewHolderä»ç¶RecyclerView临æ¶å离çæ å¿ï¼ä¾¿äºåç»ç§»é¤ææ·»å åæ¥
FLAG_ADAPTER_POSITION_UNKNOWNââViewHolderä¸ç¥é对åºçAdapterçä½ç½®ï¼ç´å°ç»å®å°ä¸ä¸ªæ°ä½ç½®
FLAG_ADAPTER_FULLUPDATEââæ¹æ³addChangePayload(null)è°ç¨æ¶è®¾ç½®
LayoutManager主è¦ä½ç¨æ¯ï¼æµéåææ¾RecyclerViewä¸itemViewï¼ä»¥åå½itemView对ç¨æ·ä¸å¯è§æ¶å¾ªç¯å¤ç¨å¤çã
å½æ们æ³å¨æäºitemä¸å ä¸äºç¹æ®çUIæ¶ï¼å¾å¾é½æ¯å¨itemViewä¸å å¸å±å¥½ï¼ç¶åéè¿è®¾ç½®å¯è§æ§æ¥å³å®åªäºä½ç½®æ¾ç¤ºä¸æ¾ç¤ºãRecyclerViewå°itemViewåè£ é¥°UIåéå¼æ¥ï¼è£ 饰UIå³ItemDecorationï¼ä¸»è¦ç¨äºç»å¶itemé´çåå²çº¿ãé«äº®æè marginçãå ¶æºç å¦ä¸ï¼
è¿å»AdapterViewçitem项æä½å¾å¾æ¯æ²¡æå¨ç»çãç°å¨RecyclerViewçItemAnimator使å¾itemçå¨ç»å®ç°åå¾ç®åèæ ·å¼ä¸°å¯ï¼æ们å¯ä»¥èªå®ä¹item项ä¸åæä½ï¼å¦æ·»å ï¼å é¤ï¼çå¨ç»ææã
Recyclerç¨äºç®¡çå·²ç»åºå¼æä¸RecyclerViewå离çï¼scrapped or detachedï¼item viewï¼ä¾¿äºéç¨ãScrapped viewæä¾éäºRecyclerViewï¼ä½è¢«æ 记为å¯ç§»é¤æå¯å¤ç¨çviewã
LayoutManagerè·åAdapteræä¸é¡¹çViewæ¶ä¼ä½¿ç¨Recyclerãå½å¤ç¨çViewææï¼cleanï¼æ¶ï¼Viewè½ç´æ¥è¢«å¤ç¨ï¼åä¹è¥View失æï¼dirtyï¼æ¶ï¼éè¦éæ°ç»å®Viewã对äºææçViewï¼å¦æä¸ä¸»å¨è°ç¨request layoutï¼åä¸éè¦éæ°æµé大å°å°±è½å¤ç¨ãå¨åæRecyclerçå¤ç¨åçä¹åï¼æ们å äºè§£ä¸å¦ä¸ä¸¤ä¸ªç±»ï¼
RecyclerViewPoolç¨äºå¤ä¸ªRecyclerViewä¹é´å ±äº«Viewãåªéè¦å建ä¸ä¸ªRecyclerViewPoolå®ä¾ï¼ç¶åè°ç¨RecyclerViewçsetRecycledViewPool(RecycledViewPool)æ¹æ³å³å¯ãRecyclerViewé»è®¤ä¼å建ä¸ä¸ªRecyclerViewPoolå®ä¾ã
éè¿æºç æ们å¯ä»¥çåºmScrapæ¯ä¸ä¸ª<viewType, List>çæ å°ï¼ mMaxScrap æ¯ä¸ä¸ª<viewType, maxNum>çæ å°ï¼è¿ä¸¤ä¸ªæååé代表å¯å¤ç¨Viewæ± çåºæ¬ä¿¡æ¯ãè°ç¨ setMaxRecycledViews(int viewType, int max) æ¶ï¼å½ç¨äºå¤ç¨ç mScrap ä¸viewType对åºçViewHolder个æ°è¶ è¿maxNumæ¶ï¼ä¼ä»å表æ«å°¾å¼å§ä¸¢å¼è¶ è¿çé¨åãè°ç¨ getRecycledView(int viewType) æ¹æ³æ¶ä» mScrap ä¸ç§»é¤å¹¶è¿åviewType对åºçListçæ«å°¾é¡¹ã
ViewCacheExtensionæ¯ä¸ä¸ªç±å¼åè æ§å¶çå¯ä»¥ä½ä¸ºViewç¼åç帮å©ç±»ãè°ç¨Recycler.getViewForPosition(int)æ¹æ³è·åViewæ¶ï¼Recyclerå æ£æ¥attached scrapåä¸çº§ç¼åï¼å¦æ没æåæ£æ¥ViewCacheExtension.getViewForPositionAndType(Recycler, int, int)ï¼å¦æ没æåæ£æ¥RecyclerViewPoolã注æï¼Recyclerä¸ä¼å¨è¿ä¸ªç±»ä¸åç¼åViewçæä½ï¼æ¯å¦ç¼åViewå®å ¨ç±å¼åè æ§å¶ã
ç°å¨å¤§å®¶çæäºRecyclerViewPoolåViewCacheExtensionçä½ç¨åï¼ä¸é¢å¼å§ä»ç»Recyclerã å¦ä¸æ¯Recyclerçå ä¸ªå ³é®æååéåæ¹æ³ï¼
è·åæ个ä½ç½®éè¦å±ç¤ºçViewï¼å æ£æ¥æ¯å¦æå¯å¤ç¨çViewï¼æ²¡æåå建æ°View并è¿åãå ·ä½è¿ç¨ä¸ºï¼
注ï¼ä»¥ä¸æ¯æ¥å¹é è¿ç¨é½å¯ä»¥å¹é positionæitemIdï¼å¦ææstableIdï¼ã