項(xiàng)目需求需要類似發(fā)布朋友圈拖拽排序的功能,故此記錄一下锣枝,感謝Android SDK的強(qiáng)大。
API鏈接:https://developer.android.com/reference/android/support/v7/widget/helper/ItemTouchHelper.Callback
效果視頻連接:https://blog.csdn.net/CCstar1/article/details/89284445
網(wǎng)上有很多使用GirdView實(shí)現(xiàn)拖拽排序效果相對來說比較復(fù)雜撇叁,在保證效率和質(zhì)量的情況下我這里選擇使用RecycleView,官方提供了TiemTouchHelper來支持此效果的完成陨闹,它的出現(xiàn)本意是上下拖拽實(shí)現(xiàn)排序楞捂,左右拖拽實(shí)現(xiàn)刪除(此處非瀑布流)趋厉。但是實(shí)現(xiàn)拖拽效果已經(jīng)綽綽有余了寨闹。下面我們開始吧君账。
TiemTouchHelper:(官方解釋)
此類是ItemTouchHelper與您的應(yīng)用程序之間的契約。它允許您控制每個ViewHolder啟用觸摸行為乡数,并在用戶執(zhí)行這些操作時(shí)接收回調(diào)椭蹄。
要控制用戶可以對每個視圖執(zhí)行哪些操作净赴,您應(yīng)該覆蓋?getMovementFlags(RecyclerView, ViewHolder)并返回適當(dāng)?shù)姆较驑?biāo)志集绳矩。(LEFT劫侧,RIGHT埋酬,START烧栋,END写妥,?UP审姓,DOWN)珍特。您可以使用?makeMovementFlags(int, int)它輕松構(gòu)建它魔吐。或者酬姆,您可以使用?ItemTouchHelper.SimpleCallback嗜桌。
如果用戶拖動item辞色,ItemTouchHelper將調(diào)用?onMove(recyclerView, dragged, target)。收到此回調(diào)后相满,您應(yīng)該將項(xiàng)目從舊位置(dragged.getAdapterPosition())移動到target.getAdapterPosition()適配器中的新位置()并調(diào)用notifyItemMoved(int, int)层亿。要控制可以刪除視圖的位置立美,您可以覆蓋?canDropOver(RecyclerView, ViewHolder, ViewHolder)。當(dāng)拖動視圖與多個其他視圖重疊時(shí)建蹄,Callback會選擇最近的視圖碌更,拖動的視圖可能會更改位置。雖然此方法適用于許多用例痛单,但如果您有自定義LayoutManager,則可以覆蓋?chooseDropTarget(ViewHolder, java.util.List, int, int)以選擇自定義放置目標(biāo)桦他。
滑動視圖時(shí),ItemTouchHelper會對其進(jìn)行動畫處理快压,直到它超出范圍,然后調(diào)用?onSwiped(ViewHolder, int)蔫劣。此時(shí)坪郭,您應(yīng)該更新適配器(例如刪除item)并調(diào)用相關(guān)的Adapter#notify事件脉幢。
自定義了Recycleview實(shí)現(xiàn)拖拽,更換位置有數(shù)據(jù)換位置然后刷新實(shí)現(xiàn)并非Recycleview自己實(shí)現(xiàn)嫌松,代碼如下:
public class DragItemRecyclerView extends RecyclerView {
? ? private ItemTouchHelper itemTouchHelper;
? ? private DragAdapter dragAdapter;
? ? private float ALPHA_FULL = 1.0f;
? ? public DragItemRecyclerView(Context context) {
? ? ? ? super(context);
? ? }
? ? public DragItemRecyclerView(Context context, @Nullable AttributeSet attrs) {
? ? ? ? super(context, attrs);
? ? }
? ? public DragItemRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
? ? ? ? super(context, attrs, defStyle);
? ? }
? ? @Override
? ? public void setAdapter(Adapter adapter) {
? ? ? ? super.setAdapter(adapter);
? ? ? ? dragAdapter = (DragAdapter) adapter;
? ? ? ? init();
? ? }
? ? private void init() {
? ? ? ? this.getItemAnimator().setChangeDuration(0);
? ? ? ? if (itemTouchHelper == null) {
? ? ? ? ? ? itemTouchHelper = new ItemTouchHelper(new ItemTouchHelperCallback());
? ? ? ? ? ? itemTouchHelper.attachToRecyclerView(this);
? ? ? ? }
? ? }
? ? public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
? ? ? ? int endPosition, startPosition;
? ? ? ? @Override
? ? ? ? public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
? ? ? ? ? ? if (dragAdapter.list != null && !TextUtils.isEmpty(dragAdapter.list.get(viewHolder.getAdapterPosition())) && dragAdapter.list.get(viewHolder.getAdapterPosition()).equals(CreateTopicActivity.ADD_IMAGE)) {
? ? ? ? ? ? ? ? return makeMovementFlags(0, 0);
? ? ? ? ? ? }
? ? ? ? ? ? if (dragAdapter.list != null && !TextUtils.isEmpty(dragAdapter.list.get(viewHolder.getAdapterPosition())) && !PhotoTools.isImageFile(dragAdapter.list.get(viewHolder.getAdapterPosition()))) {
? ? ? ? ? ? ? ? return makeMovementFlags(0, 0);
? ? ? ? ? ? }
? ? ? ? ? ? if (recyclerView.getLayoutManager() instanceof GridLayoutManager || recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
? ? ? ? ? ? ? ? final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
? ? ? ? ? ? ? ? //不需要滑動
? ? ? ? ? ? ? ? final int swipeFlags = 0;
? ? ? ? ? ? ? ? return makeMovementFlags(dragFlags, swipeFlags);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
? ? ? ? ? ? ? ? final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
? ? ? ? ? ? ? ? return makeMovementFlags(dragFlags, swipeFlags);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? @Override
? ? ? ? public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
? ? ? ? ? ? if (viewHolder.getItemViewType() != target.getItemViewType()) {
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
? ? ? ? ? ? startPosition = viewHolder.getAdapterPosition();
? ? ? ? ? ? endPosition = target.getAdapterPosition();
? ? ? ? ? ? return dragAdapter.onItemMove(startPosition, endPosition);
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void clearView(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder) {
? ? ? ? ? ? super.clearView(recyclerView, viewHolder);
? ? ? ? ? ? if (dragAdapter != null) {
? ? ? ? ? ? ? ? dragAdapter.notifyItemRangeChanged(Math.min(startPosition, endPosition), Math.abs(startPosition - endPosition) + 1);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? @Override
? ? ? ? public boolean canDropOver(RecyclerView recyclerView, ViewHolder current, ViewHolder target) {
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onSwiped(ViewHolder viewHolder, int direction) {
? ? ? ? }
? ? ? ? @Override
? ? ? ? public boolean isLongPressDragEnabled() {
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
? ? ? ? ? ? if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
? ? ? ? ? ? ? ? //自定義滑動動畫
? ? ? ? ? ? ? ? final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
? ? ? ? ? ? ? ? viewHolder.itemView.setAlpha(alpha);
? ? ? ? ? ? ? ? viewHolder.itemView.setTranslationX(dX);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? public interface ItemTouchHelperAdapter {
? ? ? ? //數(shù)據(jù)交換
? ? ? ? boolean onItemMove(int fromPosition, int toPosition);
? ? }
}
adapter相關(guān)代碼萎羔,主要是onMore調(diào)起在adapter內(nèi)方法,根據(jù)返回更換位置item的position更換數(shù)據(jù)位置然后notify贾陷,代碼如下:
? ? @Override
? ? public boolean onItemMove(int fromPosition, int toPosition) {
? ? ? ? if (list.get(toPosition).equals(CreateTopicActivity.ADD_IMAGE))
? ? ? ? ? ? return false;
? ? ? ? if (!PhotoTools.isImageFile(list.get(toPosition)))
? ? ? ? ? ? return false;
? ? ? ? //交換位置
? ? ? ? Collections.swap(list, fromPosition, toPosition);
? ? ? ? notifyItemMoved(fromPosition, toPosition);
? ? ? ? return true;
? ? }
上述第一個if是判斷是不是添加按鈕,如果是不更換髓废,需求默認(rèn)添加按鈕在最后巷懈。第二個if判斷是否是視頻慌洪,視頻需求默認(rèn)第一位也不可更換位置顶燕。
大家沒有看錯就這點(diǎn)代碼實(shí)現(xiàn)了所有功能,如果大家還有什么問題歡迎留言蒋譬。