一、基础准备


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

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

 

二、自动换行的 ViewGroup


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

 

 

完整代码如下:

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 布局文件中的效果:

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

更多相关文章

  1. Android高手进阶教程(七)之----Android(安卓)中Preferences的使
  2. textView 和 edittext 的一些属性
  3. 【进阶篇】Android学习笔记——TextInputLayout
  4. Android中 ScrollView(ListView)中嵌套ListView时显示不全的简便解
  5. Android知识体系总结(全方面覆盖Android知识结构,面试&进阶)
  6. Android:Layout_weight属性解析
  7. Android高手进阶教程(四)之----Android(安卓)中自定义属性(attr.
  8. android UI进阶之弹窗的使用(2)--实现通讯录的弹窗效果
  9. 【Android进阶】android:configChanges属性总结

随机推荐

  1. Android应用程序的内存泄漏问题
  2. android auto 能微信_5分钟搞定Flutter与
  3. 【Android(安卓)UI设计与开发】第06期:底
  4. KMM 入门(三)平台差异化实现
  5. 面试官:作为Android高级攻城狮,请你解释一
  6. (一)Android(安卓)异步消息处理
  7. Unity与Android调用交互
  8. Android第一行代码——14章继续进阶-你还
  9. android的ViewPager实现加载网络图片并自
  10. Android简单联系人操作