FrameLayout实现原理分析

FrameLayout 是 Android 中最简单的布局容器之一,它将所有添加的子视图堆叠放置,后添加的子视图会覆盖在先添加的子视图之上。下面我们将从源码层面来分析 FrameLayout 的实现原理,重点关注其测量和布局过程。

1. 测量过程(onMeasure)

FrameLayout 在测量其子视图时,通常会将父容器的测量规格直接传递给子视图,除非有特定的布局参数指定了子视图的尺寸。这意味着 FrameLayout 不会改变其子视图的大小,除非它被要求去适应某种尺寸限制。

1@Override
2protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
3    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
4    int count = getChildCount();
5    for (int i = 0; i < count; i++) {
6        View child = getChildAt(i);
7        if (mMeasureAllChildren || child.getVisibility() != GONE) {
8            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
9        }
10    }
11}

在这个方法中,FrameLayout 会遍历其所有的子视图并调用 measureChildWithMargins 方法来测量每个子视图。measureChildWithMargins 方法会考虑子视图的 LayoutParams 中定义的 margin,并使用这些值来创建一个新的测量规格。

2. 布局过程(onLayout)

在布局过程中,FrameLayout 将所有子视图定位在其左上角,然后根据子视图的大小和位置属性(如 margin)来确定最终位置。由于 FrameLayout 默认不调整子视图大小,所以子视图的定位只依赖于它们自己的测量结果和布局参数。

1@Override
2protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
3    final int count = getChildCount();
4    final int parentLeft = getPaddingLeft();
5    final int parentRight = right - left - getPaddingRight();
6    final int parentTop = getPaddingTop();
7    final int parentBottom = bottom - top - getPaddingBottom();
8    final int parentWidth = parentRight - parentLeft;
9    final int parentHeight = parentBottom - parentTop;
10
11    for (int i = 0; i < count; i++) {
12        final View child = getChildAt(i);
13        if (child.getVisibility() != GONE) {
14            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
15            final int width = child.getMeasuredWidth();
16            final int height = child.getMeasuredHeight();
17            final int childLeft = parentLeft + lp.leftMargin;
18            final int childTop = parentTop + lp.topMargin;
19            final int childRight = childLeft + width;
20            final int childBottom = childTop + height;
21            child.layout(childLeft, childTop, childRight, childBottom);
22        }
23    }
24}

在上述代码中,onLayout 方法首先获取 FrameLayout 的边界和 padding,然后遍历所有子视图并根据它们的 LayoutParams 来计算每个子视图的左上角坐标。最后,它调用 child.layout() 方法来设置子视图的最终位置。

3. 布局参数(LayoutParams)

FrameLayout 使用 LayoutParams 类来存储每个子视图的布局参数。这包括子视图的宽度、高度、margin 等属性。LayoutParams 对象允许子视图定制它们在父布局中的位置和大小。

1public static class LayoutParams extends MarginLayoutParams {
2    public LayoutParams(Context c, AttributeSet attrs) {
3        super(c, attrs);
4    }
5
6    public LayoutParams(int width, int height) {
7        super(width, height);
8    }
9
10    public LayoutParams(MarginLayoutParams source) {
11        super(source);
12    }
13
14    public LayoutParams(LayoutParams source) {
15        super(source);
16    }
17}

通过继承 MarginLayoutParamsFrameLayout.LayoutParams 可以支持 margin 属性,这对于定位子视图非常有用。

总结

FrameLayout 的实现相对简单,它主要负责将子视图按照添加顺序堆叠在一起,后添加的子视图会覆盖先前的子视图。在测量和布局过程中,FrameLayout 依赖于子视图自身的测量逻辑和 LayoutParams 中定义的属性来确定子视图的最终位置和大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值