Android 手把手進階自定義View(九)- 自動換行 ViewGroup

一、基礎準備


前三篇我們學習了 View 的三大流程:測量、佈局、繪製,本篇我們來做一個自動換行的 ViewGroup。

 

二、自動換行的 ViewGroup


具體要實現的部分是如上圖所示的尺碼部分,超過一行後會自動換到下一行。

 

 

完整代碼如下:

class FlexLayout(context: Context?, attrs: AttributeSet?) : ViewGroup(context, attrs) {

    //子view的rect
    var childrenBounds = ArrayList<Rect>()

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec)

        //已使用寬度
        var widthUsed = 0
        //已使用高度
        var heightUsed = 0
        //當前行width已使用的寬度
        var lineWidthUsed = 0
        //當前行view的高度最大值
        var lineMaxHeight = 0

        for (i in 0 until childCount) {
            //獲取子view
            val childView = getChildAt(i)
            //測量子view,因爲要換行,所以這裏的widthUsed不傳入,我們下面自己計算
            measureChildWithMargins(childView, widthMeasureSpec, 0, heightMeasureSpec, 0)

            //換行邏輯
            if (widthSpecMode != MeasureSpec.UNSPECIFIED && lineWidthUsed + childView.measuredWidth > widthSpecSize) {
                lineWidthUsed = 0
                heightUsed += lineMaxHeight
                lineMaxHeight = 0
                measureChildWithMargins(childView, widthMeasureSpec, 0, heightMeasureSpec, heightUsed)
            }

            //避免重複創建
            var childBound: Rect
            if (childrenBounds.size <= i) {
                childBound = Rect()
                childrenBounds.add(childBound)
            } else {
                childBound = childrenBounds[i]
            }

            //設置rect邊界
            childBound.set(
                lineWidthUsed, heightUsed, lineWidthUsed + childView.measuredWidth,
                heightUsed + childView.measuredHeight
            )

            //當前行使用寬度加上當前childView的測量寬度
            lineWidthUsed += childView.measuredWidth
            //計算最大的寬度
            widthUsed = Math.max(widthUsed, lineWidthUsed)
            //當前行childView的最大高度
            lineMaxHeight = Math.max(lineMaxHeight, childView.measuredHeight)

        }
        val width = widthUsed
        //viewGroup的使用高度要加上最後一行的最大高度
        val height = heightUsed + lineMaxHeight
        setMeasuredDimension(width, height)
    }


    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        for (i in 0 until childCount) {
            val childView = getChildAt(i)

            val childBounds = childrenBounds[i]
            childView.layout(childBounds.left, childBounds.top, childBounds.right, childBounds.bottom)
        }
    }

    override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
        return MarginLayoutParams(context, attrs)
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

    <com.lerendan.customviewsample.study.FlexLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:background="#9c9c9c"
                android:gravity="center"
                android:textSize="25dp"
                android:text="上海市"/>

        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:background="#FD6464"
                android:gravity="center"
                android:textSize="25dp"
                android:text="廣州市"/>

        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:background="#2196F3"
                android:gravity="center"
                android:textSize="25dp"
                android:text="深圳市深圳市"/>
        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:background="#00BCD4"
                android:gravity="center"
                android:textSize="25dp"
                android:text="北京市"/>
        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:background="#EEFF41"
                android:gravity="center"
                android:textSize="25dp"
                android:text="杭州市"/>


    </com.lerendan.customviewsample.study.FlexLayout>

</LinearLayout>

Build 後 xml 佈局文件中的效果:

可以看到 ViewGroup 的寬高都符合我們的預期。再看看實際運行效果 :

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章