今天給大家推薦一個(gè)自由拖拽,自由組合的控件,這個(gè)控件是我自定義寫的。通過它,我們可以自由拖拽,自由組合實(shí)現(xiàn)一個(gè)界面,滿足一個(gè)用戶自由組合界面的需求。這里不是通過自由拖拽控件,來快速開發(fā)一個(gè)界面,而且更人性化的讓用戶去自由組合一個(gè)界面。
前言
最近有一個(gè)項(xiàng)目,有一個(gè)主界面,界面上有很多控件或者有多個(gè) fragment 組成,大小不一,而且由于用戶需要,需要自由拖動(dòng)和自由組合,形成用戶自己需要的組合成的模樣。所以就寫了一個(gè) DragerViewLayout ,只要在 DragerViewLayout 下,寫入了多個(gè)視圖,就可以自由拖動(dòng)和組合了。DragerViewLayout 本質(zhì)上是一個(gè)相對(duì)布局,所以初始位置都可以自己按相對(duì)布局的方式來定義,然后用戶手動(dòng)拖動(dòng)后,會(huì)自動(dòng)記錄每個(gè)子視圖的位置,進(jìn)行保存,等到重新加載后,會(huì)按照記錄的位置進(jìn)行布局。
效果圖
說一千道一萬,不如看實(shí)踐,那就一起來欣賞一下效果圖的效果如何吧?
你們感覺如何?
實(shí)現(xiàn)思路
首先
首先,我們來想想,要是實(shí)現(xiàn)各個(gè)子控件和視圖之間的拖拽和交換位置,那這就意味著所有的子視圖和控件必須在一個(gè)層級(jí)之內(nèi),否則跨層級(jí)的拖拽是非常難實(shí)現(xiàn)的。所以第一個(gè)思路就是:
使用相對(duì)布局
使用相對(duì)布局,其實(shí)可以滿足所有控件都在一個(gè)層級(jí)之內(nèi)的,而且可以滿足我們初始的任何樣式的布局。況且相對(duì)布局是 Android 官方推薦使用的布局。
其次
其次,就該討論拖拽的問題了,如何實(shí)現(xiàn)拖拽呢?有沒有更好的,簡(jiǎn)單的方式呢?難道只能自己實(shí)現(xiàn)觸摸事件,判斷是哪個(gè)控件,計(jì)算 X , Y 坐標(biāo)移動(dòng)呢?非也,其實(shí)有簡(jiǎn)單的好辦法。那就是:
使用 ViewDragHelper
ViewDragHelper 是一個(gè)非常棒的東西,好用,簡(jiǎn)單,不需要你去計(jì)算。2013年谷歌 I/O 大會(huì)上介紹了兩個(gè)新的 layout: SlidingPaneLayout 和 DrawerLayout,現(xiàn)在這兩個(gè)類被廣泛的運(yùn)用,其實(shí)研究他們的源碼你會(huì)發(fā)現(xiàn)這兩個(gè)類都運(yùn)用了 ViewDragHelper 來處理拖動(dòng)。ViewDragHelper 是 framework 中不為人知卻非常有用的一個(gè)工具。
ViewDragHelper 解決了 Android 中手勢(shì)處理過于復(fù)雜的問題,在 DrawerLayout 出現(xiàn)之前,側(cè)滑菜單都是由第三方開源代碼實(shí)現(xiàn)的,其中著名的當(dāng)屬 MenuDrawer ,MenuDrawer 重寫 onTouchEvent 方法來實(shí)現(xiàn)側(cè)滑效果,代碼量很大,實(shí)現(xiàn)邏輯也需要很大的耐心才能看懂。如果每個(gè)開發(fā)人員都從這么原始的步奏開始做起,那對(duì)于安卓生態(tài)是相當(dāng)不利的。所以說 ViewDragHelper 等的出現(xiàn)反映了安卓開發(fā)框架已經(jīng)開始向成熟的方向邁進(jìn)。
關(guān)于 ViewDragHelper 的具體用法,這里不過多贅述,想了解的,在網(wǎng)上一搜,有非常多的文章都在介紹它的基本使用方法。
再次
再次,我們?cè)撊绾伟淹蟿?dòng)的視圖的位置,保存住呢?又該如何在重新打開應(yīng)用的時(shí)候按照我們自己組合和重新排列的布局顯示呢?其實(shí)方法也一樣很簡(jiǎn)單,那就是:
記住每個(gè)子控件拖拽后的位置,并保存,在 onLayout 方法中,讀取記錄的位置
在這里,我給每個(gè)視圖和控件都增加了一個(gè) tag ,在拖拽的時(shí)候根據(jù) tag 知道拖拽的是哪個(gè)控件和視圖,然后記錄位置,寫入 SharedPreferences 文件中,在 onLayout 方法中讀取文件,根據(jù)記錄的位置布局,這樣,再次打開應(yīng)用時(shí),就會(huì)根據(jù)自己拖拽和組合的方式排列。
最后
最后,有一個(gè)問題就是,相對(duì)布局會(huì)根據(jù)自己初始的位置有覆蓋層級(jí)的,先寫的在下面,后寫的控件在上面,拖拽的時(shí)候,怎么把下面的提到上面來呢?方法也很簡(jiǎn)單,那就是:
使用 child.bringToFront() 方法
bringToFront() 方法就是干這個(gè)事的,會(huì)把操作的視圖,提到最上層來。
最后的最后
最后的最后,我就不貼具體的代碼和使用方式了,代碼和使用方法都在我的 github 上,地址如下:
https://github.com/loonggg/DragerViewLayout
有興趣的同學(xué)可以去研究一下。