編輯:關於Android編程
RecyclerView
的Item或者觸摸Item的某個按鈕。 RecyclerView Item滑動刪除:RecyclerView Item滑動刪除:RecyclerView
的Item滑動刪除。
利用ItemTouchHelper綁定RecyclerView
、ItemTouchHelper.Callback
來實現UI更新,並且實現動態控制是否開啟拖拽功能和滑動刪除功能。
ItemTouchHelper
,並在構造方法傳入實現的ItemTouchHelper.Callback
。 recyclerView綁定ItemTouchHelper:itemTouchHelper.attachToRecyclerView(recyclerView)
。 自定義ItemTouchHelper.Callback
的實現接口OnItemTouchCallbackListener
,由外部更新RecyclerView
的Item。
activity_main.xml
這個沒啥好說的了吧,就是一個RecyclerView
啦。
接下來是RecyclerView
的Item的布局item.xml:
這個也不用解釋了,到時候下載看源碼,就是普通item,展示數據而已。
DefaultItemTouchHelper
:繼承ItemTouchHelper
public class DefaultItemTouchHelper extends ItemTouchHelper {
public DefaultItemTouchHelper(ItemTouchHelp.Callback callback) {
super(callback);
}
}
好嘛,這個太簡單了,基本上一行代碼都不用寫。但是這裡需要一個ItemTouchHelp.Callback
啊,所以我們還是要實現一個ItemTouchHelp.Callback
,客觀且看下文分解。
ItemTouchHelper.Callback
:繼承ItemTouchHelper.Callback
這裡是全文最重要的部分啦,要認真點看噢,先上代碼,後解釋,其他看注釋和視頻。
public class DefaultItemTouchHelpCallback extends ItemTouchHelper.Callback {
/**
* Item操作的回調
*/
private OnItemTouchCallbackListener onItemTouchCallbackListener;
/**
* 是否可以拖拽
*/
private boolean isCanDrag = false;
/**
* 是否可以被滑動
*/
private boolean isCanSwipe = false;
public DefaultItemTouchHelpCallback(OnItemTouchCallbackListener onItemTouchCallbackListener) {
this.onItemTouchCallbackListener = onItemTouchCallbackListener;
}
/**
* 設置Item操作的回調,去更新UI和數據源
*
* @param onItemTouchCallbackListener
*/
public void setOnItemTouchCallbackListener(OnItemTouchCallbackListener onItemTouchCallbackListener) {
this.onItemTouchCallbackListener = onItemTouchCallbackListener;
}
/**
* 設置是否可以被拖拽
*
* @param canDrag 是true,否false
*/
public void setDragEnable(boolean canDrag) {
isCanDrag = canDrag;
}
/**
* 設置是否可以被滑動
*
* @param canSwipe 是true,否false
*/
public void setSwipeEnable(boolean canSwipe) {
isCanSwipe = canSwipe;
}
/**
* 當Item被長按的時候是否可以被拖拽
*
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return isCanDrag;
}
/**
* Item是否可以被滑動(H:左右滑動,V:上下滑動)
*
* @return
*/
@Override
public boolean isItemViewSwipeEnabled() {
return isCanSwipe;
}
/**
* 當用戶拖拽或者滑動Item的時候需要我們告訴系統滑動或者拖拽的方向
*
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {// GridLayoutManager
// flag如果值是0,相當於這個功能被關閉
int dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlag = 0;
// create make
return makeMovementFlags(dragFlag, swipeFlag);
} else if (layoutManager instanceof LinearLayoutManager) {// linearLayoutManager
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
int orientation = linearLayoutManager.getOrientation();
int dragFlag = 0;
int swipeFlag = 0;
// 為了方便理解,相當於分為橫著的ListView和豎著的ListView
if (orientation == LinearLayoutManager.HORIZONTAL) {// 如果是橫向的布局
swipeFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
} else if (orientation == LinearLayoutManager.VERTICAL) {// 如果是豎向的布局,相當於ListView
dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
}
return makeMovementFlags(dragFlag, swipeFlag);
}
return 0;
}
/**
* 當Item被拖拽的時候被回調
*
* @param recyclerView recyclerView
* @param srcViewHolder 拖拽的ViewHolder
* @param targetViewHolder 目的地的viewHolder
* @return
*/
@Override
public boolean onMove(RecyclerView recyclerView, ViewHolder srcViewHolder, ViewHolder targetViewHolder) {
if (onItemTouchCallbackListener != null) {
return onItemTouchCallbackListener.onMove(srcViewHolder.getAdapterPosition(), targetViewHolder.getAdapterPosition());
}
return false;
}
@Override
public void onSwiped(ViewHolder viewHolder, int direction) {
if (onItemTouchCallbackListener != null) {
onItemTouchCallbackListener.onSwiped(viewHolder.getAdapterPosition());
}
}
public interface OnItemTouchCallbackListener {
/**
* 當某個Item被滑動刪除的時候
*
* @param adapterPosition item的position
*/
void onSwiped(int adapterPosition);
/**
* 當兩個Item位置互換的時候被回調
*
* @param srcPosition 拖拽的item的position
* @param targetPosition 目的地的Item的position
* @return 開發者處理了操作應該返回true,開發者沒有處理就返回false
*/
boolean onMove(int srcPosition, int targetPosition);
}
}
好,其實上面最重要的就是五個方法:
/**
* 是否可以長按拖拽排序。
*/
@Override
public boolean isLongPressDragEnabled() {}
/**
* Item是否可以被滑動(H:左右滑動,V:上下滑動)
*/
@Override
public boolean isItemViewSwipeEnabled() {}
/**
* 當用戶拖拽或者滑動Item的時候需要我們告訴系統滑動或者拖拽的方向
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {}
/**
* 當Item被拖拽的時候被回調
*/
@Override
public boolean onMove(RecyclerView r, ViewHolder rholer, ViewHolder tholder) {}
/**
* 當View被滑動刪除的時候
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}
isItemViewSwipeEnabled()
返回值是否可以拖拽排序,true可以,false不可以,isItemViewSwipeEnabled()
是否可以滑動刪除,true可以,false不可以;這兩個方法都是配置是否可以操作的。我們上面的代碼中返回了一個成員變量值,並且這個值通過外部可以修改,所以提供了外部控制的方法。
onMove()
當Item被拖拽排序移動到另一個Item的位置的時候被回調,onSwiped()
當Item被滑動刪除到不見;這兩個方法是當用戶操作了,來回調我們,我們就該去更新UI了。這裡我們提供了一個Listener去通知外部,並且返回出去了必要的值,來降低代碼耦合度。
getMovementFlags()
說明一:是當用戶拖拽或者滑動Item的時候需要我們告訴系統滑動或者拖拽的方向,那我們又知道支持拖拽和滑動刪除的無非就是LinearLayoutManager
和GridLayoutManager
了,相當於我們老早的時候用的ListView
和GridView
了。所以我們根據布局管理器的不同做了響應的區分。
getMovementFlags()
說明二:其他都好理解,就是這裡的return makeMovementFlags(dragFlag, swipeFlag);
這句話是最終的返回值,也就是它決定了我們的拖拽或者滑動的方法。第一個參數是拖拽flag,第二個是滑動的flag。
DefaultItemTouchHelper
我們記得上面定義了一個DefaultItemTouchHelper
,它的構造中需要傳一個ItemTouchHelper.Callback
,既然我們實現禮了,我們再把DefaultItemTouchHelper
做個封裝,使使用者更傻瓜式的調用。
public class DefaultItemTouchHelper extends YolandaItemTouchHelper {
private DefaultItemTouchHelpCallback itemTouchHelpCallback;
public DefaultItemTouchHelper(DefaultItemTouchHelpCallback.OnItemTouchCallbackListener onItemTouchCallbackListener) {
super(new DefaultItemTouchHelpCallback(onItemTouchCallbackListener));
itemTouchHelpCallback = (DefaultItemTouchHelpCallback) getCallback();
}
/**
* 設置是否可以被拖拽
*
* @param canDrag 是true,否false
*/
public void setDragEnable(boolean canDrag) {
itemTouchHelpCallback.setDragEnable(canDrag);
}
/**
* 設置是否可以被滑動
*
* @param canSwipe 是true,否false
*/
public void setSwipeEnable(boolean canSwipe) {
itemTouchHelpCallback.setSwipeEnable(canSwipe);
}
}
現在我們看到已經不需要傳ItemTouchHelper.Callback
給ItemTouchHelper
了,只需要傳我們在DefaultItemTouchHelpCallback
中定義好的OnItemTouchCallbackListener
就好了,而且提供了設置是否可以滑動和是否可以拖拽的方法,而OnItemTouchCallbackListener
只是通知外部滑動了、刪除了,你去更新UI吧。
這裡可以有的同學會有疑問,上面原來不是繼承ItemTouchHelper
嗎?這裡咋就變成了YolandaItemTouchHelper
了呢?因為我們看到這裡多了一句itemTouchHelpCallback = getCallback();
,這個getCallback();
這個方法是沒有的,是我們在YolandaItemTouchHelper
中自定義的,因為我們想在DefaultItemTouchHelper
中提供外部設置是否可以拖拽和滑動刪除的方法,就得拿到這個Callback
,所以我看了下源碼,我們在ItemTouchHelper
構造中把Callback
穿進去,它保存的時候一個package級別的成員變量,所以我在android.support.v7.widget.helper
包下新建了一個YolandaItemTouchHelper
類:
public class YolandaItemTouchHelper extends ItemTouchHelper {
public YolandaItemTouchHelper(Callback callback) {
super(callback);
}
public Callback getCallback() {
return mCallback;
}
}
好扯淡也扯完了,封裝也封裝完了,那麼接下來就來在Activity
中使用下咯:
沒啥好說的用itemTouchHelper.attachToRecyclerView(recyclerView)
綁定recyclerView
和ItemTouchHelper
,並且只是允許拖拽和滑動刪除Item:
DefaultItemTouchHelper itemTouchHelper = new DefaultItemTouchHelper(onItemTouchCallbackListener);
itemTouchHelper.attachToRecyclerView(recyclerView);
itemTouchHelper.setDragEnable(true);
itemTouchHelper.setSwipeEnable(true);
看到上面還缺少一個onItemTouchCallbackListener
吧,這個也比較重要。
Callback
自定義的OnItemTouchCallbackListener
刷新UI我們在自定義Callback
的時候不是在onMove()
和onSwiped()
方法中回調OnItemTouchCallbackListener
去更新UI嗎?這裡就是OnItemTouchCallbackListener
如何更新UI的操作了,完成這個操作,那麼我們的目的就達到了:
private DefaultItemTouchHelpCallback.OnItemTouchCallbackListener onItemTouchCallbackListener = new DefaultItemTouchHelpCallback.OnItemTouchCallbackListener() {
@Override
public void onSwiped(int adapterPosition) {
// 滑動刪除的時候,從數據源移除,並刷新這個Item。
if (userInfoList != null) {
userInfoList.remove(adapterPosition);
mainAdapter.notifyItemRemoved(adapterPosition);
}
}
@Override
public boolean onMove(int srcPosition, int targetPosition) {
if (userInfoList != null) {
// 更換數據源中的數據Item的位置
Collections.swap(userInfoList, srcPosition, targetPosition);
// 更新UI中的Item的位置,主要是給用戶看到交互效果
mainAdapter.notifyItemMoved(srcPosition, targetPosition);
return true;
}
return false;
}
};
這是個很簡單的問題,但每次隔一段時間後使用起來總是會出點亂子。這裡記錄下Logcat的步驟:1,在Activity裡申明tag變量(名字其實是隨便的,如下:private
第8節 桌面小工具桌面小工具是可以放置在主界面的、快速控制應用的小助手。例如我們的音樂小工具,它可以幫助用戶在桌面上就完成音樂的暫停、播放、切換等操作,而不需要啟動應用本
第7節 豎屏的播放界面播放視頻的功能放在一個單獨的Activity當中。我們將為它們設置橫豎屏兩種布局。在豎屏的時候,上半部分播放視頻,下半部分顯示視頻信息;
前段時間下載了AChartEnginee的源碼,並且對源碼的框架進行了一些了解,講解了整個框架的組成部分和每個部分的作用,最近一周則主要看了一下源碼中的demo部分,即如