概述
1.performLayout():执行控件树布局
2.mView.gatherTransparentRegion():在控件树布局完成后,如果控件树中存在SurfaceView,则需要计算窗口的透明区域
布局控件树:
调用performLayout(),这个方法内容比较简单,主要是一句:
//host为RootViewImpl的根View
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
这样就启动了这个控件树的布局流程。
layout()方法:
public void layout(int l, int t, int r, int b) {//传进来的是相对于父控件的坐标
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
//... ...
//设置mLeft、mTop、mBottom、mRight四个成员
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
//onLayout()是用于布局子控件的,所以如果不是ViewGroup则什么都不用做
onLayout(changed, l, t, r, b);
//... ...
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
//回调OnlayoutChangeListener
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLayoutChangeListeners != null) {
ArrayList<OnLayoutChangeListener> listenersCopy =
(ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
int numListeners = listenersCopy.size();
for (int i = 0; i < numListeners; ++i) {
listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
}
mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
//... ...
}
1.设置该控件坐标
2.调用子控件的layout()方法设置子控件的坐标
3.回调该控件的OnLayoutChangeListener
计算窗口的透明区域:
这个主要是针对SurfaceView的,当控件树中存在SurfaceView才会调用ViewParent.requestTransparentRegion(),才会执行计算窗口透明区域的代码。
主要是Region这个类,这个Region代表的区域是透明的区域,先设置Region为整个窗口的,然后再让控件树中的每一个View都参与计算,即把自己区域从这个Region中删掉,但是SurfaceView不一样,SurfaceView做和普通View相反的操作,即把自己的区域和Region合并,所以在SurfaceView之前被遍历的View设置的非透明区域有可能会被SurfaceView设置的透明区域覆盖。
普通View的gatherTransparentRegion()的核心代码如下:
// The SKIP_DRAW flag IS NOT set, so this view draws. We need to
// remove it from the transparent region.
final int[] location = attachInfo.mTransparentLocation;
getLocationInWindow(location);
// When a view has Z value, then it will be better to leave some area below the view
// for drawing shadow. The shadow outset is proportional to the Z value. Note that
// the bottom part needs more offset than the left, top and right parts due to the
// spot light effects.
int shadowOffset = getZ() > 0 ? (int) getZ() : 0;
region.op(location[0] - shadowOffset, location[1] - shadowOffset,
location[0] + mRight - mLeft + shadowOffset,
location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE);
SurfaceView的gatherTransparentRegion()如下:
int w = getWidth();
int h = getHeight();
if (w>0 && h>0) {
getLocationInWindow(mLocation);
// otherwise, punch a hole in the whole hierarchy
int l = mLocation[0];
int t = mLocation[1];
region.op(l, t, l+w, t+h, Region.Op.UNION);
}
View使用region和该view的区域做DIFFERENCE操作,即取region的补集
SurfaceView使用region和该SurfaceView的区域做UNION操作,即region和SurfaceView的区域的合集
SurfaceView参与控件树的测量和布局,只是不参与绘制,绘制不是在onDraw中,而是getSurfaceHolder().lockCanvas()获取Canvas向Surface绘制内容。
最后
以上就是积极铃铛为你收集整理的View的布局控件树阶段的全部内容,希望文章能够帮你解决View的布局控件树阶段所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复