前言:這個世界充滿假象,唯有痛楚不會說謊。 ——摔跤吧,爸爸
一、概述
我們在上兩篇文章對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();
}
}
至此,本文結束!下篇我們會進行探討萬能ViewHolder和adapter簡單封裝。
源碼地址:https://github.com/FollowExcellence/RecyclerViewDemo
請尊重原創者版權,轉載請標明出處:https://blog.csdn.net/m0_37796683/article/details/103990481 謝謝!
相關文章:
理解RecyclerView(一)
● RecyclerView的基礎使用、網格佈局、瀑布流佈局
理解RecyclerView(二)
● RecyclerView的ItemType(不同條目類型)
理解RecyclerView(三)
● RecyclerView的ItemDecoration分割線、增刪item動畫效果、拖拽和側滑刪除功能
理解RecyclerView(四)
● RecyclerView的自定義點擊事件、萬能ViewHolder和Adapter簡單封裝