Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> RecycleView進階三(實現不一樣的拖動排序以及側滑刪除)

RecycleView進階三(實現不一樣的拖動排序以及側滑刪除)

編輯:關於Android編程

前言:

上次呢為大家介紹了如何給RecycleView添加頭部、尾部達到裝飾的效果,那麼本章節將為大家介紹RecycleView實現不一樣的拖動排序以及側滑刪除。

首先呢我們來分析下使用ListView是如何實現拖動排序的,如果我們要使用ListView實現拖動排序,第一反應就是自定義控件了,因為android API提供的ListView是不具備有拖動排序的功能,那麼就會想到要在onTouchEvent去處理,那麼在RecycleView中是怎麼做的呢?需不需要自定義RecycleView呢?

答案是不需要。在RecycleView的jar包裡呢可以看到有ItemTouchHelper這麼一個類,那麼這個類是干嘛用的呢?根據官方的介紹,該類支持RecycleView的拖動排序以及側滑刪除的實用類。看到這裡,那麼是不是覺得RecycleView很牛逼啊,連側滑都可以用,我們平常實現側滑的時候也是需要自定義控件去實現的,但是在RecycleView裡不需要,是不是頓時覺得RecycleView的逼格就提升了,有木有這種感覺。。。微笑

OK,分析完之後呢,我們就需要去使用了,那麼如何使用呢?看我細細寫來,首先先把准備工作做好

布局:



    

item布局:

 




    

    

 

Adapter、ViewHolder、分割線處理這裡就不一一列舉了,直接進入主題,RecycleView如何實現拖動排序。

上面為大家介紹了RecycleView的jar包裡有個叫的ItemTouchHelper的類,那麼接下來就是使用這個類來實現效果了。

那麼當我們去實例化的時候就會發現這個類需要回調監聽ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(callback);,接下來就是要去定義一個回調類了

 

package com.example.recyclerviewdemo4;

import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper.Callback;

public class ItemTouchCallback extends Callback {

	// Callback回調監聽先調用的方法,用於判斷當前手勢動作
	@Override
	public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
		return 0;
	}

	// 拖動的時候回調
	@Override
	public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
			RecyclerView.ViewHolder target) {
		return false;
	}

	// 側滑的時候回調
	@Override
	public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {

	}

}
當我們繼承Callback的時候,我們需要重寫這麼幾個方法,如果需要實現長按拖動或者是側滑,就需要在getMovementFlags返回給RecycleView一個方向了,著這裡呢我們需要調用makeMovementFlags這個方法,不能調錯了方法啊,不然的話可沒有效果,這個方法需要傳入兩個參數makeMovementFlags(int dragFlags, int swipeFlags),分別是拖動的Flags,滑動的Flags,在ItemTouchHelper裡,可以看到這麼幾個常量值,分別是:

 

 

UP = 1
DOWN = 1 << 1
LEFT = 1 << 2
RIGHT = 1 << 3 DOWN,LEFT,RIGHT為什麼要做位移操作呢?拖動Item的時候是不是既有向上拖動又有向下拖動啊,側滑也是如此,所以如果要讓item可以向上拖動又可以向下拖動的話,那麼就要位運算了,即ItemTouchHelper.DOWN | ItemTouchHelper.UP,側滑也是如此ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT,那麼如果只返回一個方向值,那就只能往一個方向拖動或者側滑了,在這裡呢要實現的是拖動以及側滑,所有:

 

 

public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
	return makeMovementFlags(ItemTouchHelper.DOWN | ItemTouchHelper.UP,ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
}
還有一個要注意的地方就是在onMove的方法裡要返回true,否則沒有拖動的效果。接下來就是在Activy裡使用了:

 

 

main_rv = (RecyclerView) findViewById(R.id.main_rv);
RecycleViewAdapter mAdapter = new RecycleViewAdapter(MainActivity.this, datas);
// 設置Adapter
main_rv.setAdapter(mAdapter);
// 設置顯示的布局水平顯示
main_rv.setLayoutManager(new LinearLayoutManager(MainActivity.this));
// 添加分割線(繪制水平方向的分割線)
main_rv.addItemDecoration(new ItemDecorationDivider(MainActivity.this));
// 回調類
ItemTouchCallback callback = new ItemTouchCallback();
mItemTouchHelper = new ItemTouchHelper(callback);
// 關聯RecycleView
mItemTouchHelper.attachToRecyclerView(main_rv);
接下來就是看效果了:
\

 

拖動效果實現了,是不是還沒有交換啊,那麼接下來就是處理交換了,上面介紹了Callback裡有這個一個方法onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,RecyclerView.ViewHolder target),這個麼也就是拖動時候的回調方法,這裡呢有三個參數,第一個就不多說了,第二個參數是指我的拖動的原始位置也就是長按的那個item,target是指拖動的時候需要交換的位置。交換的事情呢就在這裡做了,那麼是不是直接在這裡作交換呢?那當然不是了,如果要做交換的話,那麼是一定需要Adapter的,如果在實例化ItemCallback的時候需要傳入Adapter,這樣是不是耦合度很高啊,這樣做就違背了RecycleView的高度解耦了。在這裡呢我就定義個回調接口,接口如下(這裡就把側滑的也一並帶進去吧):

 

public interface ItemCallback {
	// 拖動的時候回調
	void onMove(int from, int target);

	// 側滑的時候回調
	void onSwiped(int position);
}

 

接口裡要傳那些參數自定義,這裡就傳一個初始位置還有目標位置了:

 

public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
	if (mItemCallback != null) {
	    mItemCallback.onMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
	}
	return true;
}

 

那麼這個接口是不是在Activity裡實現呢?當然也是可以的,我個人建議是不要在Activity裡實現這個接口,這裡呢就在Adapter裡實現這個接口。

 

public void onMove(int from, int target) {
	// 交換數據
	Collections.swap(mDatas, from, target);
	// 移動Item
	notifyItemMoved(from, target);
}
還有就是在Activity裡要設置監聽了:

 

 

callback.setItemCallback(mAdapter);
\
效果實現,那麼在有的時候啊,需求是要點擊或者長按那個圖片的時候也要實現拖動排序的效果,那麼怎麼辦呢?在ItemTouchHelper這個類裡有startDrag(ViewHolder viewHolder)這麼一個方法,這個方法只需要傳入一個ViewHolder即可。因為點擊事件是在Adapter裡處理的,那麼Adapter是不是需要傳入ItemTouchHelper的引用的。這樣做也是會提高耦合度的,同樣的方法,可以定義回調接口,降低耦合度,接口如下:

 

 

public interface ItemHeaderIconTouchListener {
	void onTouchDrag(RecyclerView.ViewHolder holder);
}

 

Adapter回調實現

 

private ItemHeaderIconTouchListener mItemHeaderIconTouchListener;
public void setItemHeaderIconTouchListener(ItemHeaderIconTouchListener mItemHeaderIconTouchListener) {
	this.mItemHeaderIconTouchListener = mItemHeaderIconTouchListener;
}
/**
 * item綁定要顯示的數據
 */
@Override
public void onBindViewHolder(final RecyclerViewHolder viewHolder, final int position) {
	viewHolder.drag_sort_item_tv.setText(mDatas.get(position));
	//回調
	viewHolder.drag_sort_item_iv.setOnTouchListener(new OnTouchListener() {

		@Override
		public boolean onTouch(View v, MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_DOWN) {
				if (mItemHeaderIconTouchListener != null) {
					mItemHeaderIconTouchListener.onTouchDrag(viewHolder);
				}
			}
			return true;
		}
	});
}

 

Activity實現接口:

 

// 綁定回調接口
mAdapter.setItemHeaderIconTouchListener(this);
實現拖動:

 

 

@Override
public void onTouchDrag(ViewHolder holder) {
	mItemTouchHelper.startDrag(holder);
}
\

拖動效果的實現就到這裡了,寫了這麼多總算把拖動搞定了。如果我有這麼一個需求,就是當我選中item的時候將item的背景顏色改變,松開的時候改回原來的顏色,那麼這個怎麼做呢?那有些小伙伴就會認為我不是可以監聽Item的點擊事件嗎,ACTION_DOWN的時候就改變顏色,ACTION_UP的時候就變回原來的顏色嘛,這不是很簡單嗎?

 

這樣做肯定可以滴,但是既然我們使用了RecycleView,那麼就可以使用RecycleView提供的方法來處理,這樣做是不是感覺更有逼格啊大笑。那麼接下來呢就為大家介紹這兩個方法onSelectedChanged以及clearView,這兩個方法呢分別在DOWN和UP的時候回調。

 

@Override
public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
	// 處於拖動或者側滑狀態
	if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
		viewHolder.itemView.setBackgroundColor(Color.RED);
	}
	super.onSelectedChanged(viewHolder, actionState);
}

@SuppressWarnings("deprecation")
@Override
public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
	viewHolder.itemView
			.setBackgroundColor(viewHolder.itemView.getContext().getResources().getColor(R.color.colorPrimaryDark));
	super.clearView(recyclerView, viewHolder);
}
\

 

總算把拖動排序給搞定了,接下來就是側滑了,上面我們已經使用了getMovementFlags以及onMove,那麼是不是還有一個方法沒有編寫代碼邏輯啊,是的,側滑就在這裡實現。在上面講到定義了回調接口,同樣在onSwap的時候也是交給實現類(在這裡是Adapter)去處理,

Callback裡觸發回調

 

// 側滑的時候回調
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
	if (mItemCallback != null) {
		mItemCallback.onSwiped(viewHolder.getAdapterPosition());
	}
}
Adapter裡實現回調:

 

 

@Override
public void onSwiped(int position) {
	// 刪除數據
	mDatas.remove(position);
	// 刪除item
	notifyItemRemoved(position);
}
\

側滑的效果也實現了,這裡也可以加入一些特效,比如滑動刪除的動畫啊,透明度,縮放之類的。接下來就為大家介紹這麼一個方法:onChildDraw,這個方法在拖動或者側滑的時候回調用,因為這兩個操作需要對RecycleView的item進行重繪,onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY,int actionState, boolean isCurrentlyActive),這個方法呢有這麼幾個參數dX代表的是X軸的偏移量,dY代表的是Y軸的偏移量,actionState這個是當前item的狀態

 

 

ACTION_STATE_IDLE = 0 閒置狀態
ACTION_STATE_SWIPE = 1 側滑
ACTION_STATE_DRAG = 2 拖動

 

在這裡呢我們只需要側滑的狀態,OK,分析完了之後就上代碼了:

 

@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY,
		int actionState, boolean isCurrentlyActive) {
	// 側滑狀態
	if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
		View itemView = viewHolder.itemView;
		// 百分比
		float ratio = 1 - Math.abs(dY) / itemView.getWidth();
		itemView.setAlpha(ratio);
		itemView.setScaleX(ratio);
		itemView.setScaleY(ratio);
	}
	super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
\

可以看到特效實現了,但是有BUG,刪除之後後面會出現空白的地方,這個是因為在這裡只是處理了滑動狀態的,而閒置狀態還沒有做任何處理,那麼怎麼辦呢?

 

有兩個方法:

第一就是在onClearView方法裡添加這麼一段代碼

 

viewHolder.itemView.setAlpha(1);
viewHolder.itemView.setScaleX(1);
viewHolder.itemView.setScaleY(1);
第二就是在onChildDraw求百分比的時候判斷ration是否為0

 

 

if (ratio == 0) {
	ratio = 1;
}
這兩種方法都可以達到同樣的效果

 

\

好了,RecycleView實現拖動排序以及側滑刪除就到這裡了

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved