android 父视图底部,Android 自定义 View 之 Layout

public void layout(int l, int t, int r, int b) {

// 当前视图的四个顶点

int oldL = mLeft;

int oldT = mTop;

int oldB = mBottom;

int oldR = mRight;

// 1. 确定View的位置:setFrame() / setOpticalFrame()

// 即初始化四个顶点的值、判断当前View大小和位置是否发生了变化并返回

// ->>分析1、分析2

boolean changed = isLayoutModeOptical(mParent) ?

setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);

// 2. 若视图的大小和位置发生变化,会重新确定该View所有的子View在父容器的位置:onLayout()

if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {

onLayout(changed, l, t, r, b);

// 对于单一View的laytou过程:由于单一View是没有子View的,故onLayout()是一个空实现->>分析3

// 对于ViewGroup的laytou过程:由于确定位置与具体布局有关,所以onLayout()在ViewGroup为一个抽象方法,需重写实现

...

}

...

}

/**

* 分析1:setFrame()

*

* 作用:根据传入的4个位置值,设置View本身的四个顶点位置,最终确定View本身的位置

*

* @param left 相对于父视图的左侧位置

* @param top 相对于父视图的顶部位置

* @param right 相对于父视图的右侧位置

* @param bottom 相对于父视图的底部位置

*/

protected boolean setFrame(int left, int top, int right, int bottom) {

boolean changed = false;

if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {

changed = true;

...

// 通过以下赋值语句记录下了视图的位置信息,即确定View的四个顶点,从而确定了视图的位置

mLeft = left;

mTop = top;

mRight = right;

mBottom = bottom;

mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);

...

}

return changed;

}

/**

* 分析2:setOpticalFrame()

*

* 作用:根据传入的4个位置值,设置View本身的四个顶点位置,最终确定View本身的位置

*

* @param left 相对于父视图的左侧位置

* @param top 相对于父视图的顶部位置

* @param right 相对于父视图的右侧位置

* @param bottom 相对于父视图的底部位置

*/

private boolean setOpticalFrame(int left, int top, int right, int bottom) {

Insets parentInsets = mParent instanceof View ?

((View) mParent).getOpticalInsets() : Insets.NONE;

Insets childInsets = getOpticalInsets();

// 内部实际上是调用setFrame()

return setFrame(

left + parentInsets.left - childInsets.left,

top + parentInsets.top - childInsets.top,

right + parentInsets.left + childInsets.right,

bottom + parentInsets.top + childInsets.bottom);

}

/**

* 分析3:onLayout()

*

* 注:对于单一View的laytou过程

* a. 由于单一View是没有子View的,故onLayout()是一个空实现

* b. 由于在layout()中已经对自身View进行了位置计算,所以单一View的layout过程在layout()后就已完成

* c. 复写原理:遍历子View、计算当前子View的四个位置值并确定自身子View的位置(调用子 View 的 layout() 方法)

*

* @param changed 当前View的大小和位置是否改变了

* @param left 相对于父视图的左侧位置

* @param top 相对于父视图的顶部位置

* @param right 相对于父视图的右侧位置

* @param bottom 相对于父视图的底部位置

*/

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

// 1. 遍历子View:循环所有子View

for (int i = 0; i < getChildCount(); i++) {

View child = getChildAt(i);

// 2. 计算当前子View的四个位置值

// 2.1 位置的计算逻辑,需自己实现,也是自定义View的关键

...

// 2.2 对计算后的位置值进行赋值

int mLeft = left;

int mTop = top;

int mRight = right;

int mBottom = bottom;

// 3. 根据上述4个位置的计算值,设置子View的4个顶点:调用子view的layout() & 传递计算过的参数

// 即确定了子View在父容器的位置

child.layout(mLeft, mTop, mRight, mBottom);

// 该过程类似于单一View的layout过程中的layout()和onLayout(),此处不作过多描述

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值