【譯】ItemTouchHelper實(shí)現(xiàn)拖拽筆刷效果-part1

原文連接:Drag and Swipe with RecyclerView Part One: Basic ItemTouchHelper Example

? ? ? 在Android中搭配RecyclerView實(shí)現(xiàn)“拖拽”和“筆刷”動畫效果有很多指南、開源庫、示例。許多做法仍然使用老式的View.OnDragListener監(jiān)聽器以及Roman Nurikd的SwipeToDismiss開源庫,雖然這個庫一直在維護(hù)。使用新的API,但常常依賴GestureDetector類和onInterceptTouchEvent方法,或許這些實(shí)現(xiàn)非常復(fù)雜。這兒其實(shí)有一個更簡單的方法去添加這些特效到RecyclerView中。僅僅需要一個類,而且它已經(jīng)被Android官方添加到Android Support Library兼容包中了:這就是ItemTouchHelper類,這個工具類非常強(qiáng)大,它已經(jīng)實(shí)現(xiàn)了拖拽筆刷效果方便你添加到RecyclerView中。它是RecyclerView.ItemDecoration的子類。很容易集成到現(xiàn)有的LayoutManager和Adapter還有Item Animations中。為你提供拖動 — 釋放和一些其它動畫效果,本文中,我將實(shí)現(xiàn)一個ItemTouchHelper簡單示例。隨后進(jìn)一步討論它的適用范圍和探索它的更多特性。

題外話

假如你想查看完整代碼?請移步這里:Android-ItemTouchHelper-Demo?下載APK戳這里:APK

設(shè)置

如果你還沒有添加RecyclerView依賴包,請打開build.gradle文件,添加以下的配置代碼:

compile 'com.android.support:recyclerview-v7:22.2.0'

22.2.0是support包的版本號,根據(jù)你自己的情況設(shè)置,ItemTouchHelper幾乎可以和所有的RecyclerView.Adapter、LayoutManager搭配使用。本博客創(chuàng)建的其它文件都能在github中找到:https://github.com/iPaulPro/Android-ItemTouchHelper-Demo

使用ItemTouchHelper and ItemTouchHelper.Callback

? ? ?為了使用ItemTouchHelper,你需要實(shí)現(xiàn)ItemTouchHelper.Callback接口,通過這個接口,你可以監(jiān)聽“move”和 “swipe”事件,在這兒你也可以控制View的選擇狀態(tài)和覆蓋默認(rèn)動畫。根據(jù)需要你可以使用Android官網(wǎng)提供的簡單實(shí)現(xiàn),SimpleCallback,但為了學(xué)習(xí)的目地,我們還是自己實(shí)現(xiàn)。

我們必須實(shí)現(xiàn)主要的回調(diào)方法:

getMovementFlags(RecyclerView, ViewHolder)

onMove(RecyclerView, ViewHolder, ViewHolder)

onSwiped(ViewHolder, int)

我們還將使用2個幫助方法:

isLongPressDragEnabled()

isItemViewSwipeEnabled()

@Override

public int ?getMovementFlags(RecyclerView recyclerView,?

RecyclerView.ViewHolder viewHolder) {

? ? ? ? ? int dragFlags = ItemTouchHelper.UP| ItemTouchHelper.DOWN;

? ? ? ? ? int swipeFlags = ItemTouchHelper.START| ItemTouchHelper.END;

? ? ? ? ? return makeMovementFlags(dragFlags, swipeFlags);

}

ItemTouchHelper允許你判斷事件方向。但你必須覆寫getMovementFlags()方法去指定支持哪些方向。使用ItemTouchHelper.makeMovementFlags(int, int)創(chuàng)建代表方向的Flag。這里我們同時(shí)支持drag和swipe。

@Override

public boolean?isLongPressDragEnabled() {

? ? ? return true;

}

實(shí)現(xiàn)這個方法,ItemTouchHelper只能drag而不是swipe(反之亦然)所以必須正確指定是否支持drag。實(shí)現(xiàn)isLongPressDragEnabled()方法返回true去支持長按RecyclerView的item時(shí)的drag事件。

另外ItemTouchHelper.startDrag(RecyclerView.ViewHolder)方法支持手勢拖動。以后再講這部分內(nèi)容。

@Override

public boolean?isItemViewSwipeEnabled() {

? ? ? ? return true;

}

實(shí)現(xiàn)isItemViewSwipeEnabled()方法返回true開啟觸摸視圖時(shí)的swipe功能。另外ItemTouchHelper.startSwipe(RecyclerView.ViewHolder)也支持swipe事件。?

接下來onMove()onSwiped()兩個方法被用來通知底層數(shù)據(jù)改變。所以我們需要先創(chuàng)建一個接口。隨后使用鏈?zhǔn)交卣{(diào)傳遞事件。

public interface?ItemTouchHelperAdapter?{

? ? ? ? void?onItemMove(int fromPosition, int toPosition);

? ? ? ? void?onItemDismiss(int position);

}

這樣做的方式很簡單,只需要我們的RecyclerListAdapter去實(shí)現(xiàn)這個接口:

public class?RecyclerListAdapter?extends?RecyclerView.Adapter?implements ItemTouchHelperAdapter{

? ? ?// ... code

? ? ?@Override

? ? ?public void?onItemDismiss(int position) {

? ? ? ? ? ? ? ? ? mItems.remove(position);

? ? ? ? ? ? ? ? ?notifyItemRemoved(position);

? ? ? }

@Override

public boolean?onItemMove(int fromPosition, int toPosition) {

? ? ? if (fromPosition < toPosition) {

? ? ? ? ? ? ? ? for (int i = fromPosition; i < toPosition; i++) {

? ? ? ? ? ? ? ? ? ? ? Collections.swap(mItems, i, i + 1);

? ? ? ? ? ? ? ? }

? ? ? ? } else {

? ? ? ? ? ? ? ?for (int i = fromPosition; i > toPosition; i--) {

? ? ? ? ? ? ? ? ? ? ? Collections.swap(mItems, i, i - 1);

? ? ? ? ? ? ? ?}

? ? }

? ? ? ? notifyItemMoved(fromPosition, toPosition);

? ? ? ? return true;

}

調(diào)用notifyItemRemoved()notifyItemMoved()方法對Adapter來說非常重要目地是讓它意識到某些數(shù)據(jù)已被更改。同時(shí)也要注意View的位置和index在時(shí)刻變化。而不是最后的“drop”事件。

現(xiàn)在我們可以回去實(shí)現(xiàn)我們的SimpleItemTouchHelperCallback,我們同樣需要覆寫onMove()onSwiped()方法,首先添加構(gòu)造器和一個Adapter類型的字段:

private final ItemTouchHelperAdapter?mAdapter;

public SimpleItemTouchHelperCallback(?ItemTouchHelperAdapter adapter) {

? ? ? ? ? ?mAdapter= adapter;

}

隨后覆寫onMove()onSwiped()方法并通知適配器

@Override

public boolean?onMove(RecyclerView recyclerView,?RecyclerView.ViewHolder viewHolder,

RecyclerView.ViewHolder target) {

? ? ? ?mAdapter.onItemMove(viewHolder.getAdapterPosition(),

? ? ? ?target.getAdapterPosition());

? ? ? ?return true;

}

@Override

public void?onSwiped(RecyclerView.ViewHolder viewHolder,?int direction) {

? ? ? ? mAdapter.onItemDismiss(viewHolder.getAdapterPosition());

}

最后的回調(diào)接口類看起來像這樣:

使用我們寫好的回調(diào)接口,我們可以創(chuàng)建自己的ItemTouchHelper實(shí)例并調(diào)用attachToRecyclerView(RecyclerView)方法(例如在:MainFragment.java類中)

ItemTouchHelper.Callback callback =?new

SimpleItemTouchHelperCallback(adapter);

ItemTouchHelper touchHelper= new ItemTouchHelper(callback);

touchHelper.attachToRecyclerView(recyclerView);

app運(yùn)行后像這樣:

總結(jié)

這是一個ItemTouchHelper基礎(chǔ)實(shí)現(xiàn)。這下,你知道在RecyclerView中并不需要第三方庫也可以達(dá)到這種“拖拽”和“筆刷”效果。下一篇文章,我們將帶來更多的“拖拽”和“筆刷”特性。

源碼

我在github創(chuàng)建了一個開源demo,里邊的代碼就是本篇文章描述的內(nèi)容:Android-ItemTouchHelper-Demo,就寫到這里,請期待第二篇文章。

下一篇

Part Two:Handles, Grids, and Custom Animations

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容