拆零件,然后再把零件拼装回去,来来回回对其结构也就熟悉了
FrameLayout的特点
- 子View按照添加顺序层叠显示
- FrameLayout的尺寸与其最大子View(可见的)的尺寸相等(加上padding值)
- 如果要让GONE的子View参与计算,则需要把setMeasureAllChildren(boolean) ,setConsiderGoneChildrenWhenMeasuring()设置为true
- 支持通过layout_gravity控制子View的布局
根据上述特点,我也要实现一个简单的FrameLayout,应该怎么开始呢?
这里自然考虑继承ViewGroup,然后重写onMeasure,onLayout方法,而且onLayout方法必须实现(因为这是一个抽象方法,子类必须实现)
测量
这里测量的过程是:遍历该ViewGroup,调用子View的measure方法进行测量,同时通过子View的LayoutParams获取到子View的Margin信息,然后综合View的测量尺寸与Margin值,算出该ViewGroup的尺寸,然后设置该尺寸为ViewGroup的测量尺寸。
/*
* 尺寸测量
* */
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var maxWidth: Int = 0
var maxHeight: Int = 0
//遍历子View进行测量
for (i in 0 until childCount) {
val child = getChildAt(i)
if (child.visibility != View.GONE) {
//调用ViewGroup的一个实例方法(本质上是调用View的measure方法),
// 由于FrameLayout的特点,子View之间并不干扰尺寸大小,所以已经使用的空间为0
//该计算过程会计算padding和margin
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0)
var layoutParams = child.layoutParams as LayoutParams
//得到最大宽高,并考虑子View的Margin
maxWidth = Math.max(maxWidth, child.measuredWidth + layoutParams.leftMargin + layoutParams.rightMargin)
maxHeight = Math.max(maxHeight, child.measuredHeight + layoutParams.topMargin + layoutParams.bottomMargin)
//考虑FrameLayout本身的padding值
maxWidth += paddingLeft + paddingRight