九、自定義View之滑動刪除

效果圖:


一、繪制控件

圖片

1.定義SwipeLayout繼承FrameLayout。

2.在xml文件中往SwipeLayout中添加兩個控件,一個是內(nèi)容,一個是右滑才會顯示的刪除模塊。

3.在onFinishInflate()中獲取這兩個控件,該方法是在所有的控件全部映射成xml文件時調(diào)用,此時可以獲取到這兩個控件。根據(jù)擺放順序進行獲取。

4.獲取這兩個控件的寬高,進行擺放。在onSizeChanged()中獲取寬高,此方法調(diào)用時,界面已經(jīng)繪制完成,此時可以獲取到各控件的寬高。

5.在onLayout()中進行擺放。

至此,控件已經(jīng)繪制完成。

二、使用ViewDragHelper進行拖動。

1.在使用之前,需要把onInterceptTouchEvent(),onTouchEvent()交給ViewDragHelper處理。

2.創(chuàng)建callback,重寫其中的方法,對控件的拖拽進行處理。其中方法介紹

1) tryCaptureView() 指定要拖拽的控件。

2) getViewHorizontalDragRange()控制水平方向上的邊界。(無用)

3) clampViewPositionHorizontal() 控制child在水平方向上的移動 一般用于控制child水平方向的邊界

4) clampViewPositionVertical() 控制child在垂直方向上的移動,一般用于控制child垂直方向上的邊界。

5) onViewPositionChanged() child 位置改變時執(zhí)行,一般用于做伴隨移動

6) onViewReleased() 手指抬起時執(zhí)行,一般用于處理平滑移動。

?2.1 首先確定要拖拽的View:要拖拽的contentView 和deleteView

2.2 使要拖拽的view進行移動, clampViewPositionHorizontal()返回一個具體的值,如果不返回,無法移動。同時在該方法中控制控件移動的邊界。

內(nèi)容區(qū)域左側(cè)的邊界為:-deleteWidth < left < 0

刪除區(qū)域左側(cè)邊界為:contentWidth-deleteWidth < left < contentWidth

控制邊界代碼:

2.3伴隨移動,如果移動的是contentView,那么在移動contentView的同時,deleteView需要伴隨移動。同理,移動deleteView時,contentView也需要伴隨移動。

伴隨移動就是View1移動多少 那么View2就要移動多少,在View2的上下左右加上View1移動的距離dx,dy 如下代碼所示

2.4 處理手指抬起時的平滑移動問題 在onViewReleased() 中

如果手指抬起時,contentView向左移動到0-deleteWidth/2處,那么contentView需要向右緩慢滑動到left=0的位置(deleteView關(guān)閉),如圖所示,如果在deleteWidth/2 -deleteWidth處 那么deleteView打開。

使用ViewDragHelper的smoothSlideViewTo()來實現(xiàn)平滑滑動。這其中封裝了Scorller

使用smoothSlideViewTo()記得要重寫computeScroll() 固定寫法

三、處理滑動沖突。

把SwipeLayout放入ListView中后,會有滑動沖突,比如說上下兩個item的deleteView不能同時打開,還有ListView上下滑動和swipeLayout左右滑動的沖突。

3.1 處理ListView上下滑動和SwipeLayout左右滑動的沖突問題。當(dāng)左右滑動時,如果突然上下滑動了,此時事件會被ListView攔截,SwipeLayout做手指松開的處理。

解決方法:上下滑動事件由ListView處理,左右滑動事件由SwipeLayout處理,所以在左右滑動時,請求ListView不要攔截事件。這樣處理的結(jié)果就是,當(dāng)在左右滑動時,ListView是無法上下滑動的。

關(guān)鍵方法:請求父控件不要攔截事件:requestDisallowInterceptTouchEvent(true);

判斷,如果水平方向移動的dx > 垂直方向移動的dy 說明是在水平移動,事件由swipeLayout處理。

3.2 處理條目之間deleteView打開的沖突,同時只能有一個條目的deleteView可以打開。

解決方法:創(chuàng)建一個SwipeLayoutManager,用來記錄當(dāng)前打開的swipeLayout。并且當(dāng)有打開的SwipeLayout時,其它的SwipeLayout不能滑動。

1)使用單例模式創(chuàng)建SwipeLayoutManager,為了確保記錄數(shù)據(jù)的一致性。

2)在其中提供方法,記錄當(dāng)前打開的SwipeLayout

3)提供方法,如果有打開的swipeLayout則其他不能左右滑動

4)提供清空當(dāng)前打開layout的方法,已經(jīng)關(guān)閉swipeLayout的方法

5)在SwipeLayout中使用SwipeLayoutManager

??? 5.1)記錄當(dāng)前被打開的swipeLayout

在swipeLayout中提供兩個狀態(tài),記錄當(dāng)前的swipeLayout是打開還是關(guān)閉。

5.2)在移動過程中即onViewPositionChanged()中,記錄SwipeLayout的狀態(tài),并將打開的swipeLayout記錄在SwipeLayoutManager中。

5.3)處理item之間的滑動沖突,在onTouchEvent()中,如果已經(jīng)有了打開的SwipeLayout,那么onTouchEvent對swipeLayout滑動事件的處理就不實現(xiàn)。

在onInterceptTouchEvent()中先處理,以確保onTouchEvent()會被調(diào)用,當(dāng)onInterceptTouchEvent()返回true時,是將事件交給onTouchEvent()處理,因此有這種情況時,讓onInterceptTouchEvent()返回true。

然后在onTouchEvent()中處理,添加這樣一段代碼,onTouchEvent()返回true時,不處理用戶事件。

3.3 處理ListView滑動時,已經(jīng)打開的SwipeLayout關(guān)閉的滑動事件。

解決方法:給ListView添加滑動監(jiān)聽,當(dāng)滑動時,關(guān)閉已經(jīng)打開的swipeLayout。

四、接口回調(diào),告訴外界我的狀態(tài)。

4.1在SwipeLayout中定義接口。

4.2創(chuàng)建set方法,讓外界可以使用該接口

4.3 在該調(diào)用ope()和close()的地方調(diào)用它們。在打開的位置調(diào)用open(),在關(guān)閉的位置調(diào)用close()

4.4 外界使用

swipeLayout使用該接口。

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

相關(guān)閱讀更多精彩內(nèi)容

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