我是靠谱客的博主 积极铃铛,最近开发中收集的这篇文章主要介绍View的布局控件树阶段,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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的布局控件树阶段所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(59)

评论列表共有 0 条评论

立即
投稿
返回
顶部