7.Android RecyclerView滑動(dòng)刪除 (支付寶)右滑刪除和(今日頭條)拖動(dòng)排序

今天開始講RecycleView的系列教程。分割線,分組,局部刷新,動(dòng)態(tài)添加,緩存原理,抖音效果,瀑布流。嵌套,動(dòng)畫等等

支持功能

1.像qq一樣,右滑刪除

2.像支付寶一樣,拖動(dòng)排序

3.像今日頭條一樣,有些item不能拖動(dòng)

4.可以控制拖動(dòng)的方向


SnapHelper這個(gè)類:滾動(dòng)輔助類。

今天和大家一起實(shí)現(xiàn)RecyclerView可拖拽Item,主要是使用RecyclerView結(jié)合ItemTouchHelper來實(shí)現(xiàn)的




知識(shí)儲(chǔ)備:

1.Collections.swap(datas, i, i + 1);

實(shí)現(xiàn)步驟:

1.只需要給recyclerView添加一個(gè)ItemTouchHelper對(duì)象就行

實(shí)現(xiàn)側(cè)滑刪除

getMovementFlags()。確定左滑還是右滑動(dòng)

onSwiped()。? 數(shù)據(jù)移除和更新

實(shí)現(xiàn)拖動(dòng)效果:

mItemTouchHelper =?new?ItemTouchHelper(new?ItemTouchHelper.Callback() );

mItemTouchHelper.attachToRecyclerView(mRecyclerView);

2.ItemTouchHelper的callback

首先來自定義一個(gè)CallBack類,繼承與ItemTouchHepler.Callback()對(duì)象

1

2

3

@Override

public?int?getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {


}


@Override

public?boolean?onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {



}


@Override

public?void?onSwiped(RecyclerView.ViewHolder viewHolder,?int?direction) {


}

1).首先說一下getMovementFlags(),

這個(gè)方法是設(shè)置是否滑動(dòng)時(shí)間,以及拖拽的方向,所以在這里需要判斷一下是列表布局還是網(wǎng)格布局,

如果是列表布局的話則拖拽方向?yàn)镈OWN和UP,如果是網(wǎng)格布局的話則是DOWN和UP和LEFT和RIGHT,對(duì)應(yīng)這個(gè)方法的代碼如下:


@Override

????????????public?int?getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {

????????????????if?(recyclerView.getLayoutManager()?instanceof?GridLayoutManager) {

????????????????????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 =?0;

????????????????????return?makeMovementFlags(dragFlags, swipeFlags);

????????????????}

????????????}

2).而onMove()方法則是我們?cè)谕蟿?dòng)的時(shí)候不斷回調(diào)的方法,在這里我們需要將正在拖拽的item和集合的item進(jìn)行交換元素,然后在通知適配器更新數(shù)據(jù),也很簡(jiǎn)單,代碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@Override

public?boolean?onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {

????//得到當(dāng)拖拽的viewHolder的Position

????int?fromPosition = viewHolder.getAdapterPosition();

????//拿到當(dāng)前拖拽到的item的viewHolder

????int?toPosition = target.getAdapterPosition();

????if?(fromPosition < toPosition) {

????????for?(int?i = fromPosition; i < toPosition; i++) {

????????????Collections.swap(datas, i, i +?1);

????????}

????}?else?{

????????for?(int?i = fromPosition; i > toPosition; i--) {

????????????Collections.swap(datas, i, i -?1);

????????}

????}

????myAdapter.notifyItemMoved(fromPosition, toPosition);

????return?true;

}

3).onSwiped()是替換后調(diào)用的方法,可以不用管。然后我們希望在拖拽的時(shí)候?qū)⒈煌献У腎tem高亮,這樣用戶體驗(yàn)要好很多,所以我們要重寫CallBack對(duì)象中的onSelectedChanged()和clearView()方法,在選中的時(shí)候設(shè)置高亮背景色,在完成的時(shí)候移除高亮背景色,代碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

/**

?* 長(zhǎng)按選中Item的時(shí)候開始調(diào)用

?*

?* @param viewHolder

?* @param actionState

?*/

@Override

public?void?onSelectedChanged(RecyclerView.ViewHolder viewHolder,?int?actionState) {

????if?(actionState != ItemTouchHelper.ACTION_STATE_IDLE) {

????????viewHolder.itemView.setBackgroundColor(Color.LTGRAY);

????}

????super.onSelectedChanged(viewHolder, actionState);

}


/**

?* 手指松開的時(shí)候還原

?* @param recyclerView

?* @param viewHolder

?*/

@Override

public?void?clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {

????super.clearView(recyclerView, viewHolder);

????viewHolder.itemView.setBackgroundColor(0);

}

這樣就實(shí)現(xiàn)了我們的基本要求,但是實(shí)際功能中有可能存在,排頭前兩個(gè)的不需改變它的順序,即有些item允許拖拽,有些則不允許,所以我們需要重寫isLongPressDragEnabled()設(shè)置不允許長(zhǎng)按拖拽

1

2

3

4

5

6

7

8

/**

?* 重寫拖拽不可用

?* @return

?*/

@Override

public?boolean?isLongPressDragEnabled() {

????return?false;

}

?然后在重寫RecycleView的長(zhǎng)按監(jiān)聽(這個(gè)要自己寫個(gè)接口去實(shí)現(xiàn)),在返回的長(zhǎng)按方法中判斷是否為不可拖拽的item,若不是,則調(diào)用ItemTouchHelper的startDrag()方法,邏輯出入如下:

1

2

3

4

5

6

7

8

@Override

?public?void?onItemLongClick(RecyclerView.ViewHolder vh) {

?????//判斷被拖拽的是否是前兩個(gè),如果不是則執(zhí)行拖拽

?????if?(vh.getLayoutPosition() !=?0?&& vh.getLayoutPosition() !=?1) {

?????????mItemTouchHelper.startDrag(vh);


?????}

?}

5.重要的拖動(dòng)之后,數(shù)據(jù)變了。Adapter中實(shí)現(xiàn)下面的接口

RecyclerView.Adapter

@OverridepublicvoidonMove(intfromPosition,inttoPosition){/**

? ? ? ? * 在這里進(jìn)行給原數(shù)組數(shù)據(jù)的移動(dòng)

? ? ? ? */Collections.swap(mData, fromPosition, toPosition);/**

? ? ? ? * 通知數(shù)據(jù)移動(dòng)

? ? ? ? */notifyItemMoved(fromPosition, toPosition);? ? }

源碼:


publicclassMainActivityextendsAppCompatActivity{

privateContextmContext=MainActivity.this;

privateSwipeRecyclerViewmRecyclerView;

privateString[]titles={"美食","電影","酒店住宿","休閑娛樂","外賣","自助餐","KTV","機(jī)票/火車票","周邊游","美甲美睫",

"火鍋","生日蛋糕","甜品飲品","水上樂園","汽車服務(wù)","美發(fā)","麗人","景點(diǎn)","足療按摩","運(yùn)動(dòng)健身","健身","超市","買菜",

"今日新單","小吃快餐","面膜","洗浴/汗蒸","母嬰親子","生活服務(wù)","婚紗攝影","學(xué)習(xí)培訓(xùn)","家裝","結(jié)婚","全部分配"};

privateList<Subject>datas=newArrayList<>();

privateItemTouchHelpermItemTouchHelper;

privateMyAdaptermyAdapter;

@Override

protectedvoidonCreate(BundlesavedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initData();

initView();

? ? }

privatevoidinitData() {

//初始化data

for(inti=0;i<titles.length;i++) {

//動(dòng)態(tài)獲取資源ID,第一個(gè)參數(shù)是資源名,第二個(gè)參數(shù)是資源類型例如drawable,string等,第三個(gè)參數(shù)包名

intimageId=getResources().getIdentifier("ic_category_"+i,"mipmap",getPackageName());

datas.add(newSubject(titles[i],imageId));

? ? ? ? }

? ? }

privatevoidinitView() {

mRecyclerView=(SwipeRecyclerView)findViewById(recyclerView);

mRecyclerView.setLayoutManager(newLinearLayoutManager(this));

mRecyclerView.addItemDecoration(newDividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));

//? ? ? ? mRecyclerView.setLayoutManager(new GridLayoutManager(this, 4));

//? ? ? ? mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));

myAdapter=newMyAdapter(datas,mContext);

mRecyclerView.setAdapter(myAdapter);

mRecyclerView.addOnItemTouchListener(newOnRecyclerItemClickListener(mRecyclerView) {

@Override

publicvoidonItemClick(RecyclerView.ViewHoldervh) {

Toast.makeText(mContext,datas.get(vh.getLayoutPosition()).getTitle(),Toast.LENGTH_SHORT).show();

? ? ? ? ? ? }

@Override

publicvoidonItemLongClick(RecyclerView.ViewHoldervh) {

//判斷被拖拽的是否是前兩個(gè),如果不是則執(zhí)行拖拽

if(vh.getLayoutPosition()!=0&&vh.getLayoutPosition()!=1) {

mItemTouchHelper.startDrag(vh);

//獲取系統(tǒng)震動(dòng)服務(wù)

Vibratorvib=(Vibrator)getSystemService(Service.VIBRATOR_SERVICE);//震動(dòng)70毫秒

vib.vibrate(70);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? });

mItemTouchHelper=newItemTouchHelper(newItemTouchHelper.Callback() {

/**

? ? ? ? ? ? * 是否處理滑動(dòng)事件 以及拖拽和滑動(dòng)的方向 如果是列表類型的RecyclerView的只存在UP和DOWN,如果是網(wǎng)格類RecyclerView則還應(yīng)該多有LEFT和RIGHT

? ? ? ? ? ? * @param recyclerView

? ? ? ? ? ? * @param viewHolder

? ? ? ? ? ? * @return

? ? ? ? ? ? */

@Override

publicintgetMovementFlags(RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder) {

if(recyclerView.getLayoutManager()instanceofGridLayoutManager) {

finalintdragFlags=ItemTouchHelper.UP|ItemTouchHelper.DOWN|

ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT;

finalintswipeFlags=0;

returnmakeMovementFlags(dragFlags,swipeFlags);

}else{

finalintdragFlags=ItemTouchHelper.UP|ItemTouchHelper.DOWN;

finalintswipeFlags=0;

returnmakeMovementFlags(dragFlags,swipeFlags);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

@Override

publicbooleanonMove(RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder,RecyclerView.ViewHoldertarget) {

//得到當(dāng)拖拽的viewHolder的Position

intfromPosition=viewHolder.getAdapterPosition();

//拿到當(dāng)前拖拽到的item的viewHolder

inttoPosition=target.getAdapterPosition();

if(fromPosition<toPosition) {

for(inti=fromPosition;i<toPosition;i++) {

Collections.swap(datas,i,i+1);

? ? ? ? ? ? ? ? ? ? }

}else{

for(inti=fromPosition;i>toPosition;i--) {

Collections.swap(datas,i,i-1);

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

myAdapter.notifyItemMoved(fromPosition,toPosition);

returntrue;

? ? ? ? ? ? }

@Override

publicvoidonSwiped(RecyclerView.ViewHolderviewHolder,intdirection) {

//? ? ? ? ? ? ? ? int position = viewHolder.getAdapterPosition();

//? ? ? ? ? ? ? ? myAdapter.notifyItemRemoved(position);

//? ? ? ? ? ? ? ? datas.remove(position);

? ? ? ? ? ? }

/**

? ? ? ? ? ? * 重寫拖拽可用

? ? ? ? ? ? * @return

? ? ? ? ? ? */

@Override

publicbooleanisLongPressDragEnabled() {

returnfalse;

? ? ? ? ? ? }

/**

? ? ? ? ? ? * 長(zhǎng)按選中Item的時(shí)候開始調(diào)用

? ? ? ? ? ? *

? ? ? ? ? ? * @param viewHolder

? ? ? ? ? ? * @param actionState

? ? ? ? ? ? */

@Override

publicvoidonSelectedChanged(RecyclerView.ViewHolderviewHolder,intactionState) {

if(actionState!=ItemTouchHelper.ACTION_STATE_IDLE) {

viewHolder.itemView.setBackgroundColor(Color.LTGRAY);

? ? ? ? ? ? ? ? }

super.onSelectedChanged(viewHolder,actionState);

? ? ? ? ? ? }

/**

? ? ? ? ? ? * 手指松開的時(shí)候還原

? ? ? ? ? ? * @param recyclerView

? ? ? ? ? ? * @param viewHolder

? ? ? ? ? ? */

@Override

publicvoidclearView(RecyclerViewrecyclerView,RecyclerView.ViewHolderviewHolder) {

super.clearView(recyclerView,viewHolder);

viewHolder.itemView.setBackgroundColor(0);

? ? ? ? ? ? }

? ? ? ? });

mItemTouchHelper.attachToRecyclerView(mRecyclerView);

mRecyclerView.setRightClickListener(newSwipeRecyclerView.OnRightClickListener() {

@Override

publicvoidonRightClick(intposition,Stringid) {

datas.remove(position);

//? ? ? ? ? ? ? ? myAdapter.notifyItemRemoved(position);

myAdapter.notifyDataSetChanged();

Toast.makeText(mContext," position = "+position,Toast.LENGTH_SHORT).show();

? ? ? ? ? ? }

? ? ? ? });

? ? }

}


demo地址:https://github.com/pengcaihua123456/shennandadao

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容