内容简介:可以传递一个layout布局文件或者View,最终都是调用了getWindow()中的setContentView的相关方法。getWindow返回什么?getWindow返回的Window实现类PhoneWindow,该对象是在Activity的attach方法中创建的
#Activity
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
public void setContentView(View view) {
getWindow().setContentView(view);
initWindowDecorActionBar();
}
复制代码
可以传递一个layout布局文件或者View,最终都是调用了getWindow()中的setContentView的相关方法。
getWindow返回什么?
getWindow返回的Window实现类PhoneWindow,该对象是在Activity的attach方法中创建的
2、DecorView基本概念
#PhoneWindow
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//(1)创建DecorView
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
//(2)将acvivity的视图添加到DecorView的mContentParent中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
复制代码
DecorView是一个FrameLayout,是Activity的顶级view,包含标题栏和内部栏。最终也是将Activity的布局View添加到DecorView的内部栏中。
3、DecorView创建
通过installDecor进行DecorView的创建,内部调用了generateDecor方法创建了DecorView。
#PhoneWindow
protected DecorView generateDecor(int featureId) {
......
return new DecorView(context, featureId, this, getAttributes());
}
复制代码
4、DecorView添加
在Activity展示过程中调用到ActivityThread的handleResumeActivity方法
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
......
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
//(1)获取到DecorView
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//(2)然后通过WindowManager实现了DecorView的添加
wm.addView(decor, l);
......
}
}
复制代码
5、ViewRootImpl
在WindowManager添加DecorView过程中,调用了ViewRootImpl的requestLayout方法,最终调用到了ViewRootImpl的performTraversals方法。 每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系。
#ViewRootImpl
private void performTraversals() {
......
if (!mStopped || mReportNextDraw) {
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
|| mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
//view测量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
......
}
......
//view布局
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
......
//view绘制
performDraw();
......
}
复制代码
- 方法内部分别调用了View的measure、layout和draw方法
- performMeasure方法中需要传入childWidthMeasureSpec和childHeightMeasureSpec
二、View的measure流程
1、performMeasure
- DecorView的measure方法
- DecorView的onMeasure方法
- DecorView所有子View的measure方法
#ViewRootImpl
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
if (mView == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
复制代码
2、关于MeasureSpec
(1)定义和作用
- 每个View都有MeasureSpec,封装了View的规格和尺寸,其常量代表了32位int值。高2位代表了SpecMode(测量模式),低30位代表SpecSize(测量大小)
- 作用是在Measure流程中,会将View的LayoutParams根据父控件的规则转换为对应的MeasureSpec,根据MeasureSpec确定View的宽和高
- MeasureSpec受自身LayoutParams和父容器的MeasureSpec共同影响
(2)SpecMode三种模式:
- UNSPECIFIED:未指定模式,View想多大就多大,父容器不做限制
- AT_MOST:最大模式,对应于wrap_comtent属性,子View的最终大小是父View指定的SpecSize值,并且子View的大小不能大于这个值
- EXACTLY:精确模式,对应于match_parent属性和具体的数值,父容器测量出View所需要的大小,也就是SpecSize的值
3、DecorView的MeasureSpec
#ViewRootImpl
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec;
switch (rootDimension) {
case ViewGroup.LayoutParams.MATCH_PARENT:
// Window can't resize. Force root view to be windowSize.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
// Window can resize. Set max size for root view.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;
default:
// Window wants to be an exact size. Force root view to be that size.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;
}
复制代码
DecorView的MeasureSpec是由自身的LayoutParams和窗口的尺寸所决定
4、View的measure流程
(1)View的onMeasure方法
#View
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
复制代码
通过setMeasuredDimension设置View的宽高
(2)getDefaultSize
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
复制代码
- wrap_content和match_parent属性效果一样
5、ViewGroup的measure流程
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
final int size = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < size; ++i) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
}
复制代码
遍历所有子view并对VISIBILITY_MASK不为GONE的view调用measureChild()方法
protected void measureChild(View child, int parentWidthMeasureSpec,
int parentHeightMeasureSpec) {
final LayoutParams lp = child.getLayoutParams();
//根据父view的MeasureSpec和自身的LayoutParams生成相应的MeasureSpec
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
复制代码
三、View的layout流程
1、performLayout
- DecorView的layout方法
- DecorView的onLayout方法
- DecorView的layoutChildren方法
- DecorView的所有子View的Layout
(1)View的layout方法
public void layout(int l, int t, int r, int b) {
if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = 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(changed, l, t, r, b);
......
}
}
复制代码
- 根据View相对于父控件的左、上、右、下的距离进行布局
- 内部调用了View的onLayout方法,View和ViewGroup中onLayout为空实现
2、FrameLayout的onLayout方法
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
layoutChildren(left, top, right, bottom, false /* no force left gravity */);
}
void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
final int count = getChildCount();
final int parentLeft = getPaddingLeftWithForeground();
final int parentRight = right - left - getPaddingRightWithForeground();
final int parentTop = getPaddingTopWithForeground();
final int parentBottom = bottom - top - getPaddingBottomWithForeground();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
......
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
复制代码
遍历所有的子view,并调用其layout方法进行布局
四、View的draw流程
1、performDraw
ViewRootImpl的performDraw; ViewRootImpl的draw; ViewRootImpl的drawSoftware; DecorView(FrameLayout)的draw方法; DecorView(FrameLayout)的dispatchDraw方法; DecorView(FrameLayout)的drawChild方法; DecorView(FrameLayout)的所有子View的draw方法;
2、View的draw流程
public void draw(Canvas canvas) {
......
//(1)绘制背景
if (!dirtyOpaque) {
drawBackground(canvas);
}
// skip step 2 & 5 if possible (common case)
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// 调用View的onDraw方法绘制内容
if (!dirtyOpaque) onDraw(canvas);
// 绘制子View
dispatchDraw(canvas);
drawAutofilledHighlight(canvas);
// Overlay is part of the content and draws beneath Foreground
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// 绘制装饰
onDrawForeground(canvas);
// Step 7, draw the default focus highlight
drawDefaultFocusHighlight(canvas);
if (debugDraw()) {
debugDrawFocus(canvas);
}
// we're done...
return;
}
......
}
复制代码
- 绘制View的背景
- 绘制View的内容
- 绘制子View
- 绘制装饰,比如滚动条
3、ViewGroup的dispatchDraw方法
#ViewGroup
@Override
protected void dispatchDraw(Canvas canvas) {
......
for (int i = 0; i < childrenCount; i++) {
while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
final View transientChild = mTransientViews.get(transientIndex);
if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
transientChild.getAnimation() != null) {
more |= drawChild(canvas, transientChild, drawingTime);
}
transientIndex++;
if (transientIndex >= transientCount) {
transientIndex = -1;
}
}
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
more |= drawChild(canvas, child, drawingTime);
}
}
}
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
return child.draw(canvas, this, drawingTime);
}
复制代码
遍历所有子View,并调用子View的draw方法
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Pro Django
Marty Alchin / Apress / 2008-11-24 / USD 49.99
Django is the leading Python web application development framework. Learn how to leverage the Django web framework to its full potential in this advanced tutorial and reference. Endorsed by Django, Pr......一起来看看 《Pro Django》 这本书的介绍吧!