前言
話不多說,直接上圖:
	
筆者使用 RecyclerView 的 ItemTouchHelper 來實現這個效果,過程非常簡單。為了學習,這里順便實現了一下側滑刪除。
實現功能:
實現基本功能
循序漸進學習,這里我們先實現基本的功能:
布局文件
很簡單,不多說,直接上代碼:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/main_recyclerView" android:scrollbars="none" android:background="#F2F8FC"> </android.support.v7.widget.RecyclerView></LinearLayout>
item_list.xml
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="60dp" android:background="#ffffff"> <ImageView android:id="@+id/item_list_menu_imageView" android:layout_width="30dp" android:layout_height="25dp" android:layout_marginBottom="8dp" android:layout_marginStart="15dp" android:layout_marginTop="8dp" android:src="@drawable/imageview_menu" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/item_list_text_textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginStart="15dp" android:layout_marginTop="8dp" android:textColor="#000000" android:textSize="18sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@+id/item_list_menu_imageView" app:layout_constraintTop_toTopOf="parent"/> <android.support.v7.widget.SwitchCompat android:id="@+id/item_list_switchCompat" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginEnd="15dp" android:layout_marginTop="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
ItemTouchHelper
官方的API解釋:
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
這是一個給 RecyclerView 添加側滑刪除和拖拽的工具類。有了它,我們就可以很方便的實現上面的效果。 從構造器: ItemTouchHelper(ItemTouchHelper.Callback callback) 可以看出,我們需要一個 ItemTouchHelper.Callback 去構造 ItemTouchHelper 。
ItemTouchHelper.Callback 官方提供了一個實現類 ItemTouchHelper.SimpleCallback() ,它的使用很簡單,但為了得到更高的定制性,這里我們不使用它,有興趣的朋友可以去嘗試一下。
新建一個 MyItemTouchHelperCallback 類繼承 ItemTouchHelper.Callback ,這里我們關注它其中的三個方法:
在寫 MyItemTouchHelperCallback 之前我們先創建一個 IItemTouchHelperAdapter 接口,讓 RecyclerViewAdapter 實現這個接口。用于 RecyclerViewAdapter 回調。
public interface IItemTouchHelperAdapter {  /**   * 當item被移動時調用   *   * @param fromPosition 被操作的item的起點   * @param toPosition  被操作的item的終點   */  void onItemMove(int fromPosition, int toPosition);  /**   * 當item被側滑時調用   *   * @param position 被側滑的item的position   */  void onItemDismiss(int position);}在 RecyclerViewAdapter 中實現剛剛繼承的兩個方法:
 @Override  public void onItemMove(int fromPosition, int toPosition) {    Collections.swap(mList, fromPosition, toPosition);    notifyItemMoved(fromPosition, toPosition);  }  @Override  public void onItemDismiss(int position) {    mList.remove(position);    notifyItemRemoved(position);  }之后我們就可以開始編寫 MyItemTouchHelperCallback ,注釋很清楚,就不多說了。
public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback {  private IItemTouchHelperAdapter mAdapter;  public MyItemTouchHelperCallback(IItemTouchHelperAdapter mAdapter) {    this.mAdapter = mAdapter;  }  @Override  public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {    //上下拖拽,若有其他需求同理    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;    //向右側滑,若有其他需求同理    int swipeFlags = ItemTouchHelper.RIGHT;    return makeMovementFlags(dragFlags, swipeFlags);  }  @Override  public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {    //通知Adapter更新數據和視圖    mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());    //若返回false則表示不支持上下拖拽    return true;  }  @Override  public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {    //通知Adapter更新數據和視圖    mAdapter.onItemDismiss(viewHolder.getAdapterPosition());  }    @Override  public boolean isItemViewSwipeEnabled() {    //是否可以左右側滑,默認返回true    return true;  }  @Override  public boolean isLongPressDragEnabled() {    //是否可以長按上下拖拽,默認返回false    return true;  }}最后,在 Acivity 中將 ItemTouchHelper 和 RecyclerView 關聯起來
mItemTouchHelper = new ItemTouchHelper(new MyItemTouchHelperCallback(adapter));mItemTouchHelper.attachToRecyclerView(recyclerView);
運行效果:
	
完善
我們實現的的基本效果與文章開頭給出的效果還是有一點差距的,還需要實現的效果:
通過按住 item 左邊按鈕才能上下拖拽
首先修改 MyItemTouchHelperCallback 的 isLongPressDragEnabled()
@Override  public boolean isLongPressDragEnabled() {    //禁止長按item可以上下拖拽,因為我們要自定義開啟拖拽的時機    return false;  }其次新建一個OnStartDragListener接口,用于回調
public interface OnStartDragListener {  /**   * 當View需要拖拽時回調   *   * @param viewHolder The holder of view to drag   */  void onStartDrag(RecyclerView.ViewHolder viewHolder);}讓 Activity 繼承這個類,實現 onStartDrag() 方法
@Override  public void onStartDrag(RecyclerView.ViewHolder viewHolder) {    //通知ItemTouchHelper開始拖拽    mItemTouchHelper.startDrag(viewHolder);  }在 RecyclerViewAdapter 的構造方法中傳入 OnStartDragListener 的實例(即實現了該接口的Activity),給 item 左側的按鈕添加 事件監聽
public class RecyclerViewAdapter extends    RecyclerView.Adapter<RecyclerViewAdapter.IItemViewHolder> implements IItemTouchHelperAdapter {  //構造方法  public RecyclerViewAdapter(List<ItemEntity> list, OnStartDragListener mDragListener) {    mList = list;    this.mDragListener = mDragListener;  }    ...     @Override  public void onBindViewHolder(final IItemViewHolder holder, @SuppressLint("RecyclerView") final int position) {    ...    holder.menu.setOnTouchListener(new View.OnTouchListener() {      @Override      public boolean onTouch(View view, MotionEvent motionEvent) {        if (motionEvent.getAction()            == MotionEvent.ACTION_DOWN) {          //通知ItemTouchHelper開始拖拽            mDragListener.onStartDrag(holder);        }        return false;      }    });  }    ...}側滑或拖拽時被操作的 item Z軸高度增加,有明顯的陰影
要實現這個效果,筆者使用 ItemTouchHelper.Callback 提供的兩個回調方法:
首先新建一個 IItemTouchHelperViewHolder 接口用于回調,讓 RecyclerViewAdapter 的 ViewHolder 繼承它。
public interface IItemTouchHelperViewHolder {  /**   * item被選中,在側滑或拖拽過程中更新狀態   */  void onItemSelected();  /**   * item的拖拽或側滑結束,恢復默認的狀態   */  void onItemClear();}然后讓ViewHolder重寫上述的兩個方法:
 class ItemViewHolder extends RecyclerView.ViewHolder implements IItemTouchHelperViewHolder {    private TextView text;    private ImageView menu;    private SwitchCompat switchCompat;    ItemViewHolder(View itemView) {      super(itemView);      text = itemView.findViewById(R.id.item_list_text_textView);      menu = itemView.findViewById(R.id.item_list_menu_imageView);      switchCompat = itemView.findViewById(R.id.item_list_switchCompat);    }    @Override    public void onItemSelected() {      itemView.setTranslationZ(10);    }    @Override    public void onItemClear() {      itemView.setTranslationZ(0);    }}這里通過 setTranslationZ() 來改變 itemView 的高度。
之前筆者嘗試通過 setElevation() 來改變高度,但是行不通,后來查資料發現 View 的Z軸陰影 Z = elevation + translationZ 其中:
所以我們這里應該使用 setTranslationZ() 來改變 View 的Z軸高度而不是使用 setElevation() ,讀者們可以自行嘗試一下。
最后修改 MyItemTouchHelperCallback ,重寫上述的兩個方法,過程很簡單,直接看代碼:
 @Override  public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {    if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {      //不為空閑狀態,即為拖拽或側滑狀態      if (viewHolder instanceof IItemTouchHelperViewHolder) {        IItemTouchHelperViewHolder itemTouchHelperViewHolder =            (IItemTouchHelperViewHolder) viewHolder;        itemTouchHelperViewHolder.onItemSelected();      }    }    super.onSelectedChanged(viewHolder, actionState);  }  @Override  public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {    super.clearView(recyclerView, viewHolder);    if (viewHolder instanceof IItemTouchHelperViewHolder) {      IItemTouchHelperViewHolder itemTouchHelperViewHolder =          (IItemTouchHelperViewHolder) viewHolder;      itemTouchHelperViewHolder.onItemClear();    }  }最后
這里是【源碼】
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。
新聞熱點
疑難解答