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)擊上圖所示,其就會進(jìn)入選擇項:
選擇1杆怕、2格侯、3行進(jìn)行復(fù)寫,然后就寫其他自定義邏輯就完了财著。然而到了kotlin它的constructor很特別联四,可以根據(jù)語法如下書寫:
class Test constructor (private val context:Context) : ViewGroup(context){}
如此這般如何復(fù)寫三個constructor呢,實(shí)際上也很簡單:
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的高亮顯示:
這里結(jié)合前面的onLayout方法睦袖,將數(shù)據(jù)的bean作為一個tag賦值給對應(yīng)的子view上珊肃,于是每個子view擁有了此數(shù)據(jù)的屬性,我們可以根據(jù)控制每個子view的點(diǎn)擊狀態(tài)改變綁定的數(shù)據(jù)馅笙,從而控制了整個視圖的變化伦乔。
4、屏幕適配
在這里我自定義了幾種屬性:
由于本身根據(jù)子控件進(jìn)行測量顯示董习,子控件只需要控制textview的textsize就可以實(shí)現(xiàn)不同屏幕的適配了评矩,這里我封裝了一個textview屏幕適配的類:DimenUtil。
DimenUtil 根據(jù)屏幕寬度的百分比來設(shè)定本textview的字體大小阱飘,textview字體可以看作是正方形模塊,只要限定住了百分比就可以控制了它的適配虱颗,它也采取了單例的模式進(jìn)行使用沥匈,無需額外的操作,使用也非常簡單忘渔。
說明:推薦使用默認(rèn)配置達(dá)到最好的適配效果