Kotlin 自定義 標(biāo)簽viewgroup

android 對于kotlin語言做了強(qiáng)調(diào)轉(zhuǎn)移過后,kotlin逐漸取代java,成為Android開發(fā)語言中極為重要的語言之一。涉及到kotlin語法的相關(guān)知識我就不多說了,今天就項目需求套利,自定義一個viewgroup作標(biāo)簽視圖來使用進(jìn)項目中去。

1鹤耍、開寫繼承constructor

一般在java語言中肉迫,constructor直接在繼承viewgroup后會報錯,然后根據(jù)自定義快捷鍵稿黄,默認(rèn)為alt+enter【博主是用的eclipse 的keymap所以采用的 ctrl+/】就提示出來讓你選擇了喊衫。


點(diǎn)擊圖示選項.png

點(diǎn)擊上圖所示,其就會進(jìn)入選擇項:


選擇條目.png

選擇1杆怕、2格侯、3行進(jìn)行復(fù)寫,然后就寫其他自定義邏輯就完了财著。然而到了kotlin它的constructor很特別联四,可以根據(jù)語法如下書寫:
class Test constructor (private val context:Context) : ViewGroup(context){}

如此這般如何復(fù)寫三個constructor呢,實(shí)際上也很簡單:


實(shí)現(xiàn)復(fù)寫constructor.png

2撑教、核心兩方法思路與實(shí)現(xiàn):

2.1朝墩、onMesure()
根據(jù)子控件來計算父控件的大小:

    /**
     * 計算子控件大小進(jìn)行自動換行處理
     */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        val sizeWidth = MeasureSpec.getSize(widthMeasureSpec)
        val sizeHeight = MeasureSpec.getSize(heightMeasureSpec)
        val modeWidth = MeasureSpec.getMode(widthMeasureSpec)
        val modeHeight = MeasureSpec.getMode(heightMeasureSpec)

        //初始化父控件大小
        var resultWidth = 0
        var resultHeight = 0


        // 初始化行控件大小
        var itemWidth = 0
        var itemHeight = 0

        for (i in 0 until childCount) { // 遍歷 所有的子元素
            val child = getChildAt(i)
            val layoutParams = child.layoutParams as MarginLayoutParams
            measureChild(child, widthMeasureSpec, heightMeasureSpec) // 先測量

            //計算所有的子控件寬高
            val childWidth = child.measuredWidth
            val childHeight = child.measuredHeight
            // 通過margin計算所有子控件實(shí)際加上margin值的大小
            val realWidth = childWidth + layoutParams.leftMargin + layoutParams.rightMargin
            val realHeight = childHeight + layoutParams.topMargin + layoutParams.bottomMargin

            if (sizeWidth < (itemWidth + realWidth)) {//換行
                resultWidth = Math.max(realWidth, itemWidth)
                resultHeight += realHeight
                itemHeight = realHeight
                itemWidth = realWidth
            } else { // 添加
                itemWidth += realWidth
                itemHeight = Math.max(realHeight, itemHeight)
            }

            // 最后一行不換行
            if (i == childCount - 1) {
                resultWidth = Math.max(realWidth, itemWidth)
                resultHeight += itemHeight
            }
            // 通過判斷本自定義控件width||height 的屬性是否為warp_content來進(jìn)行給此view賦值,如果為march_parent或者其他屬性收苏,則使用其他屬性定義的寬高值
            // 如果僅為wrap_content則使用計算后的寬高給父控件賦值
            setMeasuredDimension(if (modeWidth == View.MeasureSpec.EXACTLY) sizeWidth else resultWidth,
                    if (modeHeight == View.MeasureSpec.EXACTLY) sizeHeight else resultHeight)
        }
    }

通過以上方法我們控制了子view的顯示亿卤,同時讓我們現(xiàn)在的viewgroup的寬高在程序中可以進(jìn)行控制處理,不會讓視圖錯亂鹿霸。

2.2排吴、onLayout()

  /**
     * 控制子view所在的位置
     */
    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        // 初始化子控件位置
        var pointWidth = 0
        var pointHeight = 0

        (0 until childCount)
                .asSequence() //序列化
                .map { getChildAt(it) }//開始遍歷子控件
                .filter { it.visibility != View.GONE } // 過濾view為gone的控件
                .forEach {
                    // 獲取子控件的測量寬高
                    val childHeight = it.measuredHeight
                    val childWidth = it.measuredWidth
                    // 使用margin的params作為定位器
                    val layoutParams = it.layoutParams as MarginLayoutParams
                    // 判斷是否換行。
                    if (pointWidth + childWidth + layoutParams.leftMargin + layoutParams.rightMargin > width) {
                        pointHeight += childHeight + layoutParams.topMargin + layoutParams.bottomMargin
                        pointWidth = 0
                    }
                    // 計算控件繪圖定位
                    val top = layoutParams.topMargin + pointHeight
                    val bottom = layoutParams.bottomMargin + pointHeight + childHeight
                    val left = layoutParams.leftMargin + pointWidth
                    val right = layoutParams.rightMargin + pointWidth + childWidth
                    it.layout(left, top, right, bottom)
                    // 通過view的tag來顯示view的實(shí)際變化
                    val tag = it.tag as CateGroyBean
                    if (tag.isChoose) it.setBackgroundResource(R.drawable.shape_selected)
                    else it.setBackgroundResource(R.drawable.shape_no_select)
                    //記錄最終view的位置
                    pointWidth += layoutParams.leftMargin + childWidth + layoutParams.rightMargin
                }

    }

通過onLayout方法記住了子view的位置懦鼠,直接底層繪圖處理定位每個子元素的位置钻哩,并可讓子view通過自己設(shè)定的方式進(jìn)行顯示。

3肛冶、控制子view的點(diǎn)擊與顯示

在使用angular過后明白了一點(diǎn)街氢,數(shù)據(jù)綁定耐前端開發(fā)人員最核心最核心的思想,于是我們這里可以借鑒angular的數(shù)據(jù)綁定思想來控制我們的view的高亮顯示:


賦值多種操作方式.png

通過數(shù)據(jù)綁定方式來控制點(diǎn)擊視圖變化.png

這里結(jié)合前面的onLayout方法睦袖,將數(shù)據(jù)的bean作為一個tag賦值給對應(yīng)的子view上珊肃,于是每個子view擁有了此數(shù)據(jù)的屬性,我們可以根據(jù)控制每個子view的點(diǎn)擊狀態(tài)改變綁定的數(shù)據(jù)馅笙,從而控制了整個視圖的變化伦乔。

4、屏幕適配

在這里我自定義了幾種屬性:


幾種自定義屬性.png

由于本身根據(jù)子控件進(jìn)行測量顯示董习,子控件只需要控制textview的textsize就可以實(shí)現(xiàn)不同屏幕的適配了评矩,這里我封裝了一個textview屏幕適配的類:DimenUtil。

DimenUtil 根據(jù)屏幕寬度的百分比來設(shè)定本textview的字體大小阱飘,textview字體可以看作是正方形模塊,只要限定住了百分比就可以控制了它的適配虱颗,它也采取了單例的模式進(jìn)行使用沥匈,無需額外的操作,使用也非常簡單忘渔。

DimenUtil部分代碼.png

說明:推薦使用默認(rèn)配置達(dá)到最好的適配效果

5高帖、最終效果

普通選定效果.gif

單選效果.gif

多選效果.gif

查看使用方式及例子請點(diǎn)擊此處

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市畦粮,隨后出現(xiàn)的幾起案子散址,更是在濱河造成了極大的恐慌,老刑警劉巖宣赔,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件预麸,死亡現(xiàn)場離奇詭異,居然都是意外死亡儒将,警方通過查閱死者的電腦和手機(jī)吏祸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钩蚊,“玉大人贡翘,你說我怎么就攤上這事蹈矮。” “怎么了鸣驱?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵泛鸟,是天一觀的道長。 經(jīng)常有香客問我踊东,道長北滥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任递胧,我火速辦了婚禮碑韵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缎脾。我一直安慰自己祝闻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布遗菠。 她就那樣靜靜地躺著联喘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辙纬。 梳的紋絲不亂的頭發(fā)上豁遭,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機(jī)與錄音贺拣,去河邊找鬼蓖谢。 笑死,一個胖子當(dāng)著我的面吹牛譬涡,可吹牛的內(nèi)容都是我干的闪幽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼涡匀,長吁一口氣:“原來是場噩夢啊……” “哼盯腌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起陨瘩,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤梦湘,失蹤者是張志新(化名)和其女友劉穎秽浇,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡檬姥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年老玛,在試婚紗的時候發(fā)現(xiàn)自己被綠了从隆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歉眷。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出底挫,到底是詐尸還是另有隱情恒傻,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布建邓,位于F島的核電站盈厘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏官边。R本人自食惡果不足惜沸手,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望注簿。 院中可真熱鬧契吉,春花似錦、人聲如沸诡渴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽妄辩。三九已至惑灵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眼耀,已是汗流浹背英支。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哮伟,地道東北人干花。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像楞黄,于是被迫代替她去往敵國和親池凄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,280評論 25 707
  • 【Android 自定義View】 [TOC] 自定義View基礎(chǔ) 接觸到一個類谅辣,你不太了解他,如果貿(mào)然翻閱源碼只...
    Rtia閱讀 3,959評論 1 14
  • 近些年來婶恼,關(guān)注自己的時候遠(yuǎn)遠(yuǎn)比關(guān)注別人的時候多桑阶。不管怎么說,我自己覺得這是個不好的習(xí)慣勾邦。一個人在原地打轉(zhuǎn)蚣录,與走出去...
    揚(yáng)思閱讀 343評論 0 3
  • 1. 風(fēng)不會等你你不會感知雨 所謂風(fēng)雨不是勢均力敵 山高水長只是一句我不能與你 ——張曉麗 藝術(shù)與傳媒學(xué)院 2....
    安徽外國語學(xué)院閱讀 817評論 0 2
  • 突然想開一場無關(guān)其他的戀愛了
    相相相柳閱讀 138評論 0 0