超簡(jiǎn)單android自定義控件流式布局SimpleFlowLayout

技術(shù)的進(jìn)步,總是由需求推動(dòng)的 ——安卓君

1、前言

流式布局是app開發(fā)中必不可少的布局方式,例如照片墻,篩選標(biāo)簽等等?;旧厦總€(gè)app里面都可以看到這樣的布局,但是android API中并沒有提供實(shí)現(xiàn)流式布局方式的控件,因此自己實(shí)現(xiàn)一個(gè)流式布局的控件就非常有必要了。本文分享筆者實(shí)現(xiàn)FlowLayout思考過程,希望能夠拋轉(zhuǎn)引玉,為大家提供一個(gè)新的思路,文章末尾有代碼鏈接。

2、效果

下面是效果圖:

SimpleFlowLayout示例圖

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,可以通過MeasureSpec.getSize(widthMeasureSpec);方法獲取。如果不是指定寬度,就無法換行擺放子控件,流式布局也就不存在了。

3.1.2 計(jì)算父控件的高度

結(jié)合效果圖看,父控件的高度由子控件行數(shù)決定的,本文假設(shè)每個(gè)子控件高度一致,行間距一致,間隔一致。

父控件高度 = paddingTop + paddingBottom + 行高*行數(shù) + 行間距*(行數(shù) - 1)
計(jì)算高度

可以看到計(jì)算高度的關(guān)鍵是\color{red}{行數(shù)}\,所以剩下的問題就是如何計(jì)算行數(shù)。

如何計(jì)算行數(shù)?

計(jì)算行數(shù)的關(guān)鍵在于知道什么時(shí)候換行,我們先看看效果圖每一行子控件實(shí)際占據(jù)的寬度


計(jì)算寬度

在FlowLayout中,一行子控件實(shí)際占據(jù)寬度為

行寬度 = 子控件寬度 + 間隔 ... (間隔數(shù)比子控件少一個(gè))

所以我們可以很容易得出這樣一個(gè)換行條件

paddingLeft + 行寬度 +  下一個(gè)子控件的寬度 + paddingRight > 父控件寬度

我們可以通過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ì)算子控件的位置,我覺得比較繁瑣,而且重復(fù)的測(cè)量也耗費(fèi)資源。我想到,在onMeasure()方法中,需要遍歷子控件計(jì)算寬高,那么為什么不在遍歷的時(shí)候,計(jì)算出每個(gè)子控件的位置,再通過setTag()方法把位置信息賦值給子控件呢?那樣的話在執(zhí)行onLayout()方法,放置子控件的時(shí)候,就可以通過遍歷子控件,getTag() 得到每個(gè)子控件的位置信息,就可以實(shí)現(xiàn)所有子控件的放置了。

如何計(jì)算每個(gè)子控件的位置?

計(jì)算子控件位置

如上圖所示,只要計(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)起來也簡(jiǎn)單。自認(rèn)為本文特別之處在于,提供新的思路,讓流式布局實(shí)現(xiàn)起來更簡(jiǎn)單優(yōu)雅

在測(cè)量子控件時(shí),計(jì)算每個(gè)控件的位置,并設(shè)置到子控件

本文主要分享思考過程、實(shí)現(xiàn)方法,不能說多完美,希望能帶給大家一點(diǎn)啟發(fā)。作者歡迎評(píng)論,探討!
源碼地址:https://github.com/f1mert/SimpleFlowLayout 歡迎點(diǎn)擊!

?著作權(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ù)。

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

  • 自定義View是Android開發(fā)中最普通的需求,靈活控制View的尺寸是開發(fā)者面臨的第一個(gè)問題,比如,為什么明明...
    看書的小蝸牛閱讀 17,589評(píng)論 6 65
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 14,200評(píng)論 1 92
  • 該文為匯總網(wǎng)上優(yōu)秀的資源所得,喜歡請(qǐng)關(guān)注原作者,我記錄下來主要是為了以后我自己查找用的ref 參考啟艦Androi...
    richy_閱讀 1,215評(píng)論 3 16
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,689評(píng)論 1 32
  • iOS布局體系的概覽 在我的CSDN博客中的幾篇文章分別介紹MyLayout布局體系中的視圖從一個(gè)方向依次排列...
    歐陽大哥2013閱讀 11,046評(píng)論 11 91

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