一:前言
之前在很多項(xiàng)目中發(fā)現(xiàn)了滑動(dòng)退出當(dāng)前頁(yè)面功能蹦肴,但是并未去了解具體實(shí)現(xiàn)使用到了哪些砚哗,直到前不久接手的項(xiàng)目的也使用到了這一功能缸濒,才了解到ViewDragHelper這一強(qiáng)大的自定義ViewGroup神器锅知。包括實(shí)現(xiàn)類似于QQ側(cè)滑妇拯,懸浮按鈕等都離不開(kāi)這一神器幻馁,好記性不如爛筆頭洗鸵,這里記錄一下學(xué)習(xí)ViewDragHelper的過(guò)程,希望大家一起成長(zhǎng)仗嗦!
what膘滨?
ViewDragHelper是什么?我們先看一下谷歌官方的解釋:
立馬打開(kāi)我的百度翻譯:
what the fuck铲咨?好吧,看到這我直接忽略百度翻譯蜓洪,咨詢了一下英語(yǔ)八級(jí)的同學(xué)鸣驱,得到牛逼的翻譯:ViewDragHelper是編寫(xiě)自定義ViewGroups一個(gè)實(shí)用工具類。它定義了一組有用的操作和狀態(tài)追蹤蝠咆,允許用戶在父ViewGroup中拖動(dòng)并且重新定位子View(child view)。
為什么說(shuō)得到了牛逼的翻譯呢北滥,因?yàn)檫@個(gè)工具類牛逼啊刚操,號(hào)稱是自定義ViewGroup拖動(dòng)的一個(gè)神器,比如在DrawerLayout中的一系列拖動(dòng)事件都是利用VDH(ViewDragHelper再芋,簡(jiǎn)稱VDH)完成的菊霜。那么我們就一步一步來(lái)揭開(kāi)它的神秘面紗~~
首先看看他的api:
好心熊已經(jīng)給大家打上最簡(jiǎn)單的注釋了,如果需要詳細(xì)了解济赎,還望各位同僚們動(dòng)動(dòng)手指鉴逞,去百度!K狙怠9辜瘛!
哇壳猜,看到了無(wú)數(shù)的api勾徽,那么我們先從最簡(jiǎn)單的開(kāi)始吧。就是實(shí)現(xiàn)一個(gè)DragView繼承LinearLayout统扳,看看如何使用ViewDragHelper實(shí)現(xiàn)DragView吧喘帚。
第一步:新建類繼承LinearLayout,實(shí)現(xiàn)構(gòu)造方法:
public class DragView extends LinearLayout{
public DragView(Context context) {
this(context,null);
}
publicDragView(Context context,@Nullable AttributeSet attrs) {
super(context,attrs,0);
}
public DragView(Context context,@NullableAttributeSet attrs, int defStyleAttr) {
super(context,attrs,defStyleAttr);
init();
}
private void init(){};
}
那么我們?nèi)绾稳?chuàng)建一個(gè)ViewDragHelper呢咒钟,直接new的話會(huì)發(fā)現(xiàn)并沒(méi)有吹由,這是因?yàn)樗臉?gòu)造方法私有化啦。我們觀察其源碼就可以發(fā)現(xiàn)兩個(gè)獲取到其實(shí)例對(duì)象的方法:
看看需要的參數(shù)都是啥朱嘴,ViewGroup:也就是你真在創(chuàng)建的這個(gè)自定義ViewGroup——DragView倾鲫,所以直接傳入this即可。 ?cb是callBack啦,看到前面的方法介紹级乍,大家肯定也知道cb就是用來(lái)處理各類事件觸發(fā)后的回調(diào)處理舌劳。 ?float sensitivity:這個(gè)是敏感度值,一般傳入1.0f玫荣,傳入的值越大甚淡,敏感度越高。
我們還可以看到一個(gè)mTouchSlop捅厂,這個(gè)值是什么贯卦,又在哪里初始化呢?
繼續(xù)追蹤源碼焙贷,可以先后看到如下代碼:
簡(jiǎn)單理解即為應(yīng)該觸發(fā)移動(dòng)時(shí)間的最短距離撵割,如果小于這個(gè)距離就不觸發(fā)移動(dòng)控件,ViewPager控件就是利用這個(gè)距離來(lái)判斷是否翻頁(yè)辙芍。
額啡彬,。故硅。咱們見(jiàn)好就收庶灿,回到創(chuàng)建ViewDragHelper,那么我們自己先創(chuàng)建一個(gè)試試:
在上面的init方法中創(chuàng)建:
private void init(){
dragHelper=ViewDragHelper.create(this,1.0f, newViewDragHelper.Callback() {
@Override
public booleantryCaptureView(Viewchild, intpointerId) {
return false;
}
});
};
傳遞一個(gè)cb吃衅,重寫(xiě)其抽象方法tryCaptureView往踢,系統(tǒng)會(huì)依次列出這個(gè)父容器的子視圖,你需要指定當(dāng)前傳入的這個(gè)視圖是否可以被拖動(dòng)徘层,如果可以拖動(dòng)就返回true峻呕,否則就返回false”返回兩個(gè)參數(shù),child是正在被捕捉的view趣效,pointerid是當(dāng)前按下點(diǎn)的id瘦癌。
我們返回ture試試,跷敬∨搴叮看看子View能不能滑動(dòng)。
這里我們把代碼補(bǔ)全干花,特別簡(jiǎn)單妄帘。
test_layout.xml:
布局文件中只有兩個(gè)TextView,一個(gè)給它取了個(gè)名字池凄。
我們想實(shí)現(xiàn)滑動(dòng)抡驼,還必須重寫(xiě)兩個(gè)方法:
clampViewPositionHorizontal
clampViewPositionVertical
我們 還需要攔截事件教給VDH肿仑,在OnTouchEvent中把事件交個(gè)VDH完成:
那么我們運(yùn)行程序致盟,發(fā)現(xiàn)兩個(gè)TextView都可以拖動(dòng)了碎税。
如果我們想要給指定控件拖動(dòng)呢,我們還記得tryCaptureView中的兩個(gè)參數(shù)嗎馏锡,可以通過(guò)child.getId() ==R.id.xxx來(lái)指定可拖動(dòng)控件雷蹂。
總結(jié):我們最簡(jiǎn)單的一個(gè)ViewDragHelper的使用到此已經(jīng)完成了,我們可以自己參閱源碼來(lái)了解各個(gè)api的作用是什么杯道,謝謝匪煌。