前言
RecyclerView依靠ItemTouchHelper,實現item的拖動與滑動功能。
使用ItemTouchHelper實現上下拖動的例子
首先我們需要繼承重寫 ItemTouchHelper.Callback
public class QuickReplyItemTouchCallback extends ItemTouchHelper.Callback {
private QuickReplyAdapter mAdapter;
private boolean mIsLongPressDragEnabled = true;
public QuickReplyItemTouchCallback(QuickReplyAdapter adapter) { //傳入適配器
mAdapter = adapter;
}
public void setLongPressDragEnabled(boolean isLongPressDragEnabled) {
mIsLongPressDragEnabled = isLongPressDragEnabled;
}
@Override
public boolean isItemViewSwipeEnabled() { //是否啓用左右滑動
return false;
}
@Override
public boolean isLongPressDragEnabled() { //返回設置是否長按拖動Item上下移動
return mIsLongPressDragEnabled;
}
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
//在這個回調方法裏我們返回我們需要的使用的動作功能
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; //拖動 這裏設置的UP 與 DOWN 表示允許上下拖動
int swipeFlags = ItemTouchHelper.ACTION_STATE_IDLE; //滑動 這裏設置的ACTION_STATE_IDLE 表示我們將滑動動作設置爲空閒
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
//用於上下移動Item的回調方法,在這個方法裏我們要主動將Adapter裏的數據互相替換位置
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
//返回 true表示我們已經將Adapter裏的數據互相替換位置
return true;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
//因爲我們不需要處理滑動,所以此處不寫邏輯
}
}
Adapter更換位置的實現
/**
* 提供給QuickReplyItemTouchCallback類使用的移動Item位置的方法
* @param fromPosition
* @param toPosition
*/
public void onItemMove(int fromPosition, int toPosition) {
Collections.swap(mList, fromPosition, toPosition);//更換我們數據List的位置
notifyItemMoved(fromPosition, toPosition); //更換Adapter Item的視圖位置
if (mOnChangeDataPositionListener != null){
mOnChangeDataPositionListener.onChange(mList);
}
}
在Activity裏給RecyclerView添加ItemTouchHelper.Callback
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
mQuickReplyRecyclerView.setLayoutManager(linearLayoutManager);
mQuickReplyAdapter = new QuickReplyAdapter();
mQuickReplyRecyclerView.setAdapter(mQuickReplyAdapter);
mCallback = new QuickReplyItemTouchCallback(mQuickReplyAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mCallback);
itemTouchHelper.attachToRecyclerView(mQuickReplyRecyclerView);
使用ItemTouchHelper實現左右滑動的例子
下面的這個例子是改變需要出現的View的寬度
public class SwitchListItemTouchCallback extends ItemTouchHelper.Callback {
private int mWidth = 0;
@Override
public boolean isLongPressDragEnabled() {
return false;
}
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.ACTION_STATE_IDLE;
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { //判斷活動狀態爲左右滑動
Context context = recyclerView.getContext();
if (mWidth == 0) {
mWidth = UnitConversionUtil.dip2px(context, 80); //Button顯示後最大的寬度。這裏用了一個dp轉px工具類
}
if (dX == 0){ //有時候點擊也會被觸發成swipe,這裏判斷不發生偏移量就跳過
return;
}
boolean isLeft = dX < 0;
SwitchListAdapter.ViewHolder itemViewHolder = (SwitchListAdapter.ViewHolder) viewHolder;
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) itemViewHolder.mDeleteBtn.getLayoutParams();
if (isLeft) {
layoutParams.width = Math.min((int) Math.abs(dX), mWidth);
} else {
layoutParams.width = Math.max((int) (mWidth - dX), 0);
}
itemViewHolder.mDeleteBtn.setLayoutParams(layoutParams);
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
// super.clearView(recyclerView, viewHolder);
}
}
滾動整個View來實現,這個效果的關鍵點是那個需要隱藏或者顯示的View 需要在父類佈局的外面
佈局例子:
關鍵點 app:layout_constraintLeft_toRightOf="parent"
<ImageButton
android:id="@+id/delete_btn"
android:layout_width="80dp"
android:layout_height="0dp"
android:background="@color/color_text_yellow"
android:src="@drawable/ic_delete_2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
代碼
@Override
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
Context context = recyclerView.getContext();
if (mWidth == 0) {
mWidth = UnitConversionUtil.dip2px(context, 80);
}
if (dX == 0){ //有時候點擊也會被觸發成swipe,這裏判斷不發生偏移量就跳過
return;
}
boolean isLeft = dX < 0;
SwitchListAdapter.ViewHolder itemViewHolder = (SwitchListAdapter.ViewHolder) viewHolder;
if (isLeft) {
itemViewHolder.rootView.setScrollX(Math.min((int) Math.abs(dX), mWidth));
} else {
itemViewHolder.rootView.setScrollX(Math.max((int) (mWidth - dX), 0));
}
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
End