前言:这个世界充满假象,唯有痛楚不会说谎。 ——摔跤吧,爸爸
一、概述
我们在上两篇文章对RecyclerView详细介绍了,包含了基本用法,各种布局管理器的使用以及不同itemType条目类型,那么下面我们会继续对RecyclerView的添加分割线、动画效果、添加拖拽和删除功能进行讲解。(源码在文章最后给出)
二、ItemDecoration分割线
通常我们添加分割线都是在item的布局里面添加,这样相对简单,但是有可能增加布局的层级,性能不好而且不太优雅,RecyclerView提供了添加分割线的API:
DividerItemDecoration decoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
recyclerView.addItemDecoration(decoration);
DividerItemDecoration只有一个构造方法,它是继承自RecyclerView.ItemDecoration类,是官方提供的一个分割线实现类,个人也可以根据需要自定义。
- DividerItemDecoration(Context context, int orientation) orientation表示分割线的方向,这个需要和RecyclerView的线性方向一致,VERTICAL表示垂直方向,HORIZONTAL表示水平方向。
- setDrawable(Drawable drawable) 上面的分割线默认是灰色的,通过这个方法可以根据你的需要设置不同的颜色,注意drawable不能为null。
通过setDrawable()
改变不同的颜色:
decoration.setDrawable(ContextCompat.getDrawable(this, R.drawable.divider_item_decoration));
我们将第一篇中的线性布局例子,更改一下,加入分割线,如下左图为分割线原始颜色,右图为自定义drawable颜色:
divider_item_decoration.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="line" >
<stroke android:color="#2196F3" android:width="1dp"/><!--stroke 的 width 是线条的宽度-->
<size android:height="2dp"/><!--size 的 height 是整个drawable的高度-->
<!--注意:如果size高度与笔划宽度相同或小于笔划宽度,则不会显示线条-->
</shape>
部分代码:ItemDecorationActivity.java
(源码在文章最后给出)
//创建布局管理器-线性布局
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//设置分割线
DividerItemDecoration decoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
//decoration.setDrawable(ContextCompat.getDrawable(this, R.drawable.divider_item_decoration));//自定义颜色
recyclerView.addItemDecoration(decoration);
//设置数据
List<String> stringList = new ArrayList<>();
for (int i = 0; i < 50; i++) {
stringList.add("第 " + i + " 个item");
}
ItemDecorationAdapter adapter = new ItemDecorationAdapter(this, stringList);
recyclerView.setAdapter(adapter);
三、ItemAnimator动画
RecyclerView默认情况下,当增加或者删除Item时,带有动画效果。如果要定制某些其他效果的动画,需要扩展继承RecyclerView.ItemAnimator类,并通过setItemAnimator(ItemAnimator animator)
设置所定制的动画。设置动画API:
recyclerView.setItemAnimator(ItemAnimator animator);
在item添加、移出和改变时产生动画效果,注意:需要使用下面特定的API来才能显示RecyclerView增删动画相对应的效果。
- notifyItemInserted(int position): 增加某一条数据动画使用notifyItemInserted(),否则没有效果;
- notifyItemRemoved(int position): 删除某一条数据动画使用notifyItemRemoved(),否则没有效果;
- notifyItemChanged(int position): 更新某一条数据动画使用notifyItemRemoved(),否则没有效果。
那么我们就在item点击事件中这三种动作模拟一下,在Adapter中设置三种类型,根据不同的类型进行不同的操作:
//设置item的增加,删除,改变的动画
switch(mItem_Animator_type){
case ITEM_ADD://增加
mData.add(position, "new item " + position);
notifyItemInserted(position);//增加动画使用notifyItemInserted()更新数据,否则没有效果
break;
case ITEM_REMOVE://移出
mData.remove(position);
notifyItemRemoved(position);//删除动画使用notifyItemRemoved()更新数据,否则没有效果
break;
case ITEM_NOTIFY://改变
mData.remove(position);
mData.add(position, "change item " + position);
notifyItemChanged(position);
break;
}
效果如下:
这里为了演示三种效果,先点击头部“添加”,“移除”,“改变”;会先设置Adapter中的类型mItem_Animator_type
是那种效果,然后adapter中点击item时会根据类型进行不同的操作。(源码在文章最后给出)
四、拖拽和侧滑删除功能
Android默认提供了ItemTouchHelper类,使得RecyclerView能轻易实现滑动和拖拽功能,下面我们实现上下拖拽和侧滑删除功能。
4.1实现ItemTouchHelper.Callback
创建自定义类,并且继承ItemTouchHelper类,重写下面的几种方法,先来看看它们表示的含义:
- getMovementFlags(): 设置支持滑动和拖拽的方向,ItemTouchHelper.UP:上移,ItemTouchHelper.DOWN:下移,ItemTouchHelper.LEFT:左移,ItemTouchHelper.RIGHT:右移;
- onMove(): 拖拽时回调;
- onSwiped(): 滑动时回调;
- onSelectedChanged(): 状态变化时回调,可以做一些状态变化时的处理,比如拖拽时变化颜色背景,有三个状态:ACTION_STATE_IDLE:空闲状态,ACTION_STATE_SWIPE:滑动状态,ACTION_STATE_DRAG拖拽状态;
- clearView(): 用户交互结束时回调,可以做一些结束清除操作,比如拖拽后结束后还原背景色;
- isLongPressDragEnabled():是否支持长按拖拽,默认为true。如果不允许则可以重写该方法并返回false。
首先同过构造方法设置Adapter给自定义类,下面需要使用到相关数据:
public MyItemTouchCallback(LinearVerticalAdapter adapter) {
this.adapter = adapter;
}
然后重写getMovementFlags()
设置拖拽和滑动的方向,如果是网格布局则设置所有方向(DOWN 、UP、RIGHT 、LEFT)都能拖拽,其他则只能上下拖拽,通过makeMovementFlags()
返回设置的拖拽和滑动的方向,当然这里你也可以加入你需要的逻辑来更改不同的效果。
//设置支持滑动和拖拽的方向
//ItemTouchHelper.UP:上移,ItemTouchHelper.DOWN:下移,ItemTouchHelper.LEFT:左移,ItemTouchHelper.RIGHT:右移
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlag;//拖拽方向
int swipeFlag;//滑动方向
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {//网格布局时可以左右上下拖拽
dragFlag = ItemTouchHelper.DOWN | ItemTouchHelper.UP
| ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT;
swipeFlag = 0;
} else {//其他布局时,只能上下拖拽
dragFlag = ItemTouchHelper.DOWN | ItemTouchHelper.UP;
swipeFlag = ItemTouchHelper.END;//滑动结束
}
return makeMovementFlags(dragFlag, swipeFlag);//返回拖拽和滑动的方向
}
接着重写onMove()
拖拽回调,在拖拽时不断回调这个方法,将正在拖拽的item和集合的item进行元素交换,然后通知适配器不断更新数据:
//拖拽时回调,在拖拽时不断回调这个方法
//我们需要将正在拖拽的item和集合的item进行元素交换,然后通知适配器不断更新数据
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//当前拖拽item的position
int fromPosition = viewHolder.getAdapterPosition();
//拖拽到位置
int toPosition = target.getAdapterPosition();
//根据位置重新排序更新数据
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(adapter.getData(), i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(adapter.getData(), i, i - 1);
}
}
recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition);
return true;
}
再实现onSwiped()
方法,滑动时回调,我们演示的是侧滑删除,则在滑动结束时移出数据:
//滑动时回调
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
if (direction == ItemTouchHelper.END) {//滑动结束后移出数据,这里演示的是侧滑删除
adapter.getData().remove(position);
adapter.notifyItemRemoved(position);
}
}
实现onSelectedChanged()
方法,状态变化时回调:在拖拽是改变背景颜色
//状态变化时回调
//ACTION_STATE_DRAG(拖拽状态) ACTION_STATE_IDLE(空闲状态) ACTION_STATE_SWIPE(滑动状态)
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {//拖拽时设置背景颜色
viewHolder.itemView.setBackgroundColor(Color.BLUE);
}
}
最后实现clearView()
方法,用户交互item结束时,动画也结束了,将背景色设置为原色,用户交互时会回调这个方法:
//用户交互结束时回调,即手指松开时
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setBackgroundColor(0);
}
4.2设置给RecyclerView
那么整个自定义的拖拽侧滑删除类就实现了,我们将这个类设置给RecyclerView就可以实现效果了;
//拖拽实现类
ItemTouchHelper helper = new ItemTouchHelper(new MyItemTouchCallback(adapter));
helper.attachToRecyclerView(recyclerView);
效果如下:
给出自定义类的完成代码:MyItemTouchCallback.java
public class MyItemTouchCallback extends ItemTouchHelper.Callback {
private final LinearVerticalAdapter adapter;
public MyItemTouchCallback(LinearVerticalAdapter adapter) {
this.adapter = adapter;
}
//设置支持滑动和拖拽的方向
//ItemTouchHelper.UP:上移,ItemTouchHelper.DOWN:下移,ItemTouchHelper.LEFT:左移,ItemTouchHelper.RIGHT:右移
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlag;//拖拽方向
int swipeFlag;//滑动方向
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {//网格布局时可以左右上下拖拽
dragFlag = ItemTouchHelper.DOWN | ItemTouchHelper.UP
| ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT;
swipeFlag = 0;
} else {//其他布局时,只能上下拖拽
dragFlag = ItemTouchHelper.DOWN | ItemTouchHelper.UP;
swipeFlag = ItemTouchHelper.END;//滑动结束
}
return makeMovementFlags(dragFlag, swipeFlag);//返回拖拽和滑动的方向
}
//拖拽时回调,在拖拽时不断回调这个方法
//我们需要将正在拖拽的item和集合的item进行元素交换,然后通知适配器不断更新数据
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//当前拖拽item的position
int fromPosition = viewHolder.getAdapterPosition();
//拖拽到位置
int toPosition = target.getAdapterPosition();
//根据位置重新排序更新数据
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(adapter.getData(), i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(adapter.getData(), i, i - 1);
}
}
recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition);
return true;
}
//滑动时回调
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
if (direction == ItemTouchHelper.END) {//滑动结束后移出数据,这里演示的是侧滑删除
adapter.getData().remove(position);
adapter.notifyItemRemoved(position);
}
}
//状态变化时回调
//ACTION_STATE_DRAG(拖拽状态) ACTION_STATE_IDLE(空闲状态) ACTION_STATE_SWIPE(滑动状态)
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {//拖拽时设置背景颜色
viewHolder.itemView.setBackgroundColor(Color.BLUE);
}
}
//用户交互结束时回调,即手指松开时
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setBackgroundColor(0);
}
//是否支持长按拖拽,默认返回true
@Override
public boolean isLongPressDragEnabled() {
return super.isLongPressDragEnabled();
}
}
点关注,不迷路
好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是人才。
我是suming,感谢各位的支持和认可,您的点赞、评论、收藏【一键三连】就是我创作的最大动力,我们下篇文章见!
如果本篇博客有任何错误,请批评指教,不胜感激 !
要想成为一个优秀的安卓开发者,这里有必须要掌握的知识架构,一步一步朝着自己的梦想前进!Keep Moving!
相关文章:
理解RecyclerView(一)
● RecyclerView的基础使用、网格布局、瀑布流布局
理解RecyclerView(二)
● RecyclerView的ItemType(不同条目类型)
理解RecyclerView(三)
● RecyclerView的ItemDecoration分割线、增删item动画效果、拖拽和侧滑删除功能
理解RecyclerView(四)
● RecyclerView的自定义点击事件、万能ViewHolder和Adapter简单封装