技術(shù)的進(jìn)步箱蝠,總是由需求推動(dòng)的 ——安卓君
1、前言
流式布局是app開發(fā)中必不可少的布局方式汇陆,例如照片墻怒炸,篩選標(biāo)簽等等≌贝基本上每個(gè)app里面都可以看到這樣的布局阅羹,但是android API中并沒(méi)有提供實(shí)現(xiàn)流式布局方式的控件,因此自己實(shí)現(xiàn)一個(gè)流式布局的控件就非常有必要了教寂。本文分享筆者實(shí)現(xiàn)FlowLayout思考過(guò)程灯蝴,希望能夠拋轉(zhuǎn)引玉,為大家提供一個(gè)新的思路,文章末尾有代碼鏈接孝宗。
2、效果
下面是效果圖:
3耕肩、分析
實(shí)現(xiàn)自定義控件肯定要從View的繪制原理開始思考因妇,關(guān)于View的繪制原理這里就不做介紹了。首先可以確定的是我們要實(shí)現(xiàn)的是一個(gè)ViewGroup猿诸,多個(gè)標(biāo)簽(子控件(View)) 被放置到ViewGroup中婚被。所以要實(shí)現(xiàn)的有:
-
1.測(cè)量父控件(ViewGroup)的大小
-
2.放置子控件(View)
體現(xiàn)在代碼中就是實(shí)現(xiàn)父控件的兩個(gè)方法:
-
1.onMeasure()
-
2.onLayout()
3.1、計(jì)算父控件的寬高
3.1.1 計(jì)算父控件寬度
流式布局寬度一般都是指定的梳虽,match_parent 或者具體數(shù)值址芯。測(cè)量模式為MeasureSpec.EXACTLY
,可以通過(guò)MeasureSpec.getSize(widthMeasureSpec);
方法獲取窜觉。如果不是指定寬度谷炸,就無(wú)法換行擺放子控件,流式布局也就不存在了禀挫。
3.1.2 計(jì)算父控件的高度
結(jié)合效果圖看旬陡,父控件的高度由子控件行數(shù)決定的,本文假設(shè)每個(gè)子控件高度一致语婴,行間距一致描孟,間隔一致。
父控件高度 = paddingTop + paddingBottom + 行高*行數(shù) + 行間距*(行數(shù) - 1)
可以看到計(jì)算高度的關(guān)鍵是,所以剩下的問(wèn)題就是如何計(jì)算行數(shù)砰左。
如何計(jì)算行數(shù)?
計(jì)算行數(shù)的關(guān)鍵在于知道什么時(shí)候換行匿醒,我們先看看效果圖每一行子控件實(shí)際占據(jù)的寬度
在FlowLayout中,一行子控件實(shí)際占據(jù)寬度為
行寬度 = 子控件寬度 + 間隔 ... (間隔數(shù)比子控件少一個(gè))
所以我們可以很容易得出這樣一個(gè)換行條件
paddingLeft + 行寬度 + 下一個(gè)子控件的寬度 + paddingRight > 父控件寬度
我們可以通過(guò)for循環(huán)遍歷子控件集合計(jì)算出總行數(shù)缠导,當(dāng)我們得出行數(shù)時(shí)廉羔,就可以計(jì)算出父控件的高度,測(cè)量寬高的工作就完成了僻造。
3.2 放置子控件
放置子控件蜜另,最終調(diào)用
layout(int l, int t, int r, int b)
所以只要得到每個(gè)子控件的位置信息就可以最終展現(xiàn)出流式布局适室,很多人在實(shí)現(xiàn)FlowLayout時(shí),會(huì)在這里重新測(cè)量再計(jì)算子控件的位置举瑰,我覺(jué)得比較繁瑣捣辆,而且重復(fù)的測(cè)量也耗費(fèi)資源。我想到此迅,在onMeasure()方法中汽畴,需要遍歷子控件計(jì)算寬高,那么為什么不在遍歷的時(shí)候耸序,計(jì)算出每個(gè)子控件的位置忍些,再通過(guò)setTag()
方法把位置信息賦值給子控件呢?那樣的話在執(zhí)行onLayout()
方法坎怪,放置子控件的時(shí)候罢坝,就可以通過(guò)遍歷子控件,getTag()
得到每個(gè)子控件的位置信息搅窿,就可以實(shí)現(xiàn)所有子控件的放置了嘁酿。
如何計(jì)算每個(gè)子控件的位置?
如上圖所示男应,只要計(jì)算出子控件的寬高闹司,我們很容易就能得出left,top,bottom,right值沐飘。
4.實(shí)現(xiàn)單選和多選
如何實(shí)現(xiàn)子控件的單選功能游桩?
可以借鑒RadioGroup實(shí)現(xiàn)原理,也可以換一種思路耐朴,直接繼承RadioGroup就可以實(shí)現(xiàn)單選的功能借卧,添加RadioButton作為子控件,相當(dāng)于把RadioGroup改造成具有流式布局功能的控件筛峭。
如何實(shí)現(xiàn)子控件的多選功能谓娃?
如果添加的子控件都是CheckBox,就可以實(shí)現(xiàn)多選的功能蜒滩。
5.總結(jié)
FlowLayout算不上非常復(fù)雜的控件滨达,原理也很簡(jiǎn)單,一個(gè)是計(jì)算父容器的寬高俯艰,一個(gè)是獲取子控件的位置捡遍。本文從筆者實(shí)際業(yè)務(wù)出發(fā),行間距竹握,間隔都是在自定義屬性中設(shè)置的固定值画株,實(shí)現(xiàn)起來(lái)也簡(jiǎn)單。自認(rèn)為本文特別之處在于,提供新的思路谓传,讓流式布局實(shí)現(xiàn)起來(lái)更簡(jiǎn)單優(yōu)雅
在測(cè)量子控件時(shí)蜈项,計(jì)算每個(gè)控件的位置,并設(shè)置到子控件
本文主要分享思考過(guò)程续挟、實(shí)現(xiàn)方法紧卒,不能說(shuō)多完美,希望能帶給大家一點(diǎn)啟發(fā)诗祸。作者歡迎評(píng)論跑芳,探討!
源碼地址:https://github.com/f1mert/SimpleFlowLayout 歡迎點(diǎn)擊直颅!