temTouchHelper,可以很好的處理RecyclerView的item的滑動拖拽功能。
ItemTouchHelper是android.support.v7.widget.helper包中的一個類,但現在android官方文檔搜索,你會發現有兩個ItemTouchHelper,其中是這個包下,另一個是androidx.recyclerview.widget包下的,根據官網說法androidx是新推出的軟件包結構,一下support包都向androidx下遷移。不過現在support現在還是可以用的,Google給開發者一定的遷移時間。
ItemTouchHelper的構造方法需要傳入ItemTouchHelper.Callback來實現對拖拽的監聽。
現在就來看看ItemTouchHelper.Callback的一些方法
ItemTouchHelper.Callback是一個抽象類或者匿名內部類實現它,都必須實現它下面幾個抽象方法
//拖拽的標誌
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
//移動的監聽
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
// 滑動的回調
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction)
簡單的使用
長按可以進行拖拽交換位置,左右可以滑動刪除
適配器代碼
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {
private ArrayList<String> lists;
public RecyclerViewAdapter(ArrayList<String> lists) {
this.lists = lists;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycle, parent, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv.setText(lists.get(position));
}
@Override
public int getItemCount() {
return lists.size();
}
/** 刪除數據
* @param position
*/
public final void delData(int position) {
lists.remove(position);
notifyItemRemoved(position);
}
/** 移動進行數據交換
* @param fromPosition
* @param toPosition
*/
public final void move(int fromPosition, int toPosition) {
Collections.swap(lists, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
}
class MyViewHolder extends RecyclerView.ViewHolder {
AppCompatTextView tv;
private MyViewHolder(View itemView) {
super(itemView);
tv = itemView.findViewById(R.id.tv);
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecyclerViewAdapter recyclerViewAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recycler_view);
//模擬數據
ArrayList<String> lists = new ArrayList<>();
for (int i = 0; i < 10; i++) {
lists.add("item" + i);
}
recyclerViewAdapter = new RecyclerViewAdapter(lists);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(recyclerViewAdapter);
final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
/**
*
* @param recyclerView 關聯的recyclerView
* @param viewHolder 操作的viewHolder對象
* @return 返回運動方向標誌的組合,通過makeMovementFlags(dragFlags, swipeFlags)進行組合
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//拖拽的方法標記
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//滑動方向標記
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//通過makeMovementFlags方法將將方向標記進行組合,並將複合的值返回
return makeMovementFlags(dragFlags, swipeFlags);
}
/**
* @param recyclerView 關聯的recyclerView
* @param viewHolder 要移動的viewHolder對象
* @param target 移動到的目標ViewHolder對象
* @return 返回true 纔會執行ItemTouchHelper.Callback的onMoved方法,
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
recyclerViewAdapter.move(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
/**
* @param viewHolder 滑動的viewHolder對象
* @param direction 移動的方向標識
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
recyclerViewAdapter.delData(viewHolder.getAdapterPosition());
}
});
//關聯RecyclerView
itemTouchHelper.attachToRecyclerView(recyclerView);
}
}
如果想操作item條目是想讓條目高亮怎麼辦,如下面效果?
想實現這種效果就要重寫ItemTouchHelper.Callback的兩個方法
// 拖拽或者滑動時調用
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState)
//拖拽或者滑動結束後調用
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
具體實現
/**
* @param viewHolder 操作的ViewHolder對象
* @param actionState 當前的狀態, ItemTouchHelper.ACTION_STATE_IDLE,閒置狀態
* ItemTouchHelper.ACTION_STATE_SWIPE,開始滑動狀態
* ItemTouchHelper.ACTION_STATE_DRAG,開始拖拽
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
//如果不是現實狀態
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
//設置背景顏色爲藍色
viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getResources().getColor(android.R.color.holo_blue_light));
if (viewHolder instanceof RecyclerViewAdapter.MyViewHolder) {
RecyclerViewAdapter.MyViewHolder myViewHolder = (RecyclerViewAdapter.MyViewHolder) viewHolder;
//設置字體爲白色
myViewHolder.tv.setTextColor(Color.WHITE);
}
}
super.onSelectedChanged(viewHolder, actionState);
}
/** 還原狀態
* @param recyclerView
* @param viewHolder
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
viewHolder.itemView.setBackgroundColor(Color.TRANSPARENT);
if (viewHolder instanceof RecyclerViewAdapter.MyViewHolder) {
RecyclerViewAdapter.MyViewHolder myViewHolder = (RecyclerViewAdapter.MyViewHolder) viewHolder;
myViewHolder.tv.setTextColor(Color.BLACK);
}
super.clearView(recyclerView, viewHolder);
}
上面代碼可以看到在onSelectedChanged
中獲得viewHolder對象,就可以對RecyclerView的條目進行一些操作,如上面背景顏色的改變,還可以設置條目的一些動畫效果,當然一定要記得再clearView
還原條目的改變,否則回出現一些奇怪的情況,因爲RecyclerView條目是View是複用的。
非長按拖拽效果
ItemTouchHelper 默認是長按觸發拖拽,當然我們可以設置非長按拖拽效果,例如按住一個圖片進行拖拽
實現方法
1 在適配器重寫這個圖片的OnTouchListener
方法
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
holder.tv.setText(lists.get(position));
//設置holder.img 的OnTouchListener方法
holder.img.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//dragListener 是適配器內部接口
if (dragListener != null) {
dragListener.onDrag(holder);
}
}
return false;
}
});
}
public interface DragListener {
/**
* 使用接口回調的方式將ViewHolder返回
* @param holder
*/
void onDrag(MyViewHolder holder);
}
private DragListener dragListener;
public void setDragListener(DragListener dragListener) {
this.dragListener = dragListener;
}
2 在MainActivity中設置接口回調
recyclerViewAdapter.setDragListener(new RecyclerViewAdapter.DragListener() {
@Override
public void onDrag(RecyclerViewAdapter.MyViewHolder holder) {
// 手動的條用ItemTouchHelper的開始拖拽方法
itemTouchHelper.startDrag(holder);
}
});