一、基础准备


  • 《Android 手把手进阶自定义View(六)- measure 测量过程解析》
  • 《Android 手把手进阶自定义View(七)- layout 布局过程解析》
  • 《Android 手把手进阶自定义View(八)- draw 绘制过程解析》

前三篇我们学习了 View 的三大流程:测量、布局、绘制,本篇我们来做一个自动换行的 ViewGroup。

 

二、自动换行的 ViewGroup


Android 手把手进阶自定义View(九)- 自动换行 ViewGroup_第1张图片

具体要实现的部分是如上图所示的尺码部分,超过一行后会自动换到下一行。

 

 

完整代码如下:

class FlexLayout(context: Context?, attrs: AttributeSet?) : ViewGroup(context, attrs) {    //子view的rect    var childrenBounds = ArrayList()    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"?>                                                

Build 后 xml 布局文件中的效果:

Android 手把手进阶自定义View(九)- 自动换行 ViewGroup_第2张图片

可以看到 ViewGroup 的宽高都符合我们的预期。再看看实际运行效果 :

Android 手把手进阶自定义View(九)- 自动换行 ViewGroup_第3张图片

更多相关文章

  1. [置顶] 我的Android进阶之旅------>Android电话窃听实例
  2. android根据字体大小设置控件高度
  3. 【进阶篇】Android学习笔记——TextInputLayout
  4. android默认字体大小、高度、宽度
  5. 获取Android 手机屏幕宽度和高度以及获取Android手机序列号
  6. Android获取屏幕宽度的4种方法

随机推荐

  1. [Exception Android 20] - Error:Executi
  2. Android中调用摄像头并实现对焦拍照
  3. 关于android的audiotrack播放声音断断续
  4. (4.2.3)【android开源工具】Android快速开
  5. Android:使用Intents进行共享(Share With I
  6. android 禁用解锁
  7. 主程序与widget
  8. Android 获取时间实时更新UI
  9. android之弹出气泡PopupWindow
  10. Android相关网络资源整理