view 绘制主要流程
- measure 计算view的大小
- layout 计算view的位置
- draw 绘制view
1.Activity.java##setContentView()中会创建DecorView, 通过LayoutInflater将xml文件解析出来,构建LinearLayout整个view树
2.Activity.java##resume() 中会将view 添加到window中
view 绘制流程前因后果
view 绘制的流程主要发生在ViewRootImpl.java中
在3中情况下会调用ScheduleTraversal()
- requestLayout
- requestFocus
- invalidate
void setView(....){
// 在添加到window之前先进行一次layout,确保在接收到其他输入事件之前重新layout
requestLayout();
mSession.addToDisplay(...)
}
// 非常有意思的一个函数
// 首先从名称说起Schedule,部署计划,确实如此
// 这里用到了Handler机制的里的同步屏障[同步屏障:调整Message优先级的一种机制,设置同步屏障后,消息机制在处理消息的时候,会优先处理异步消息]
// 这个函数主要做了一下几件事情
// 1. 设置同步屏障
// 2. 在Chorographer中消息会最终设置成异步消息
// 3. mTraversalRunnable 回调执行方法doTraversal(). View绘制的核心函数
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 1 设置同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 2.设置异步消息
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
}
// 取消同步屏障, 执行performTraversals() view的绘制生命周期
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
view绘制流程performTraversals
ViewRootImpl.java
// 先吐槽一下这个函数的代码是在太长了,说好的面向对象的呢
private void performTraversals(){
// 忽略。。。
Rect frame = mWinFrame;
// 1 计算desiredWindowWidth以及desiredWindowHeight, 以及相应标志
if (mFirst) {
// 第一次请求测量,布局, 绘制流程
mFullRedrawNeeded = true;
mLayoutRequested = true;
// 如果窗口的类型是有状体栏的, 那么Activity的窗口宽度和高度就是除了状态栏
// lp.type == TYPE_STATUS_BAR_PANEL || lp.type == TYPE_INPUT_METHOD || lp.type == TYPE_VOLUME_OVERLAY;
if (shouldUseDisplaySize(lp)) {
Point size = new Point();
mDisplay.getRealSize(size);
desiredWindowWidth = size.x;
desiredWindowHeight = size.y;
} else {
// 否则Activity的宽高是整个屏幕的宽高
desiredWindowWidth = mWinFrame.width();
desiredWindowHeight = mWinFrame.height();
}
// ....忽略
} else {
// 如果不是第一次请求绘制流程外,宽高会在winFrame中保存, 即上一次的长度
desiredWindowWidth = frame.width();
desiredWindowHeight = frame.height();
// 注意这里的mWidth和mHeight是每次wms服务计算出来的
if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
// 当宽或者高繁盛变化了,则将设置相应的标志
// 重新绘制标志,layout请求的标志, window尺寸可能发生变化标志
mFullRedrawNeeded = true;
mLayoutRequested = true;
windowSizeMayChange = true;
}
}
// 2. 判断屏幕是否发生变化
boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
// 接上,比如当发生了主懂requestLayout,或者屏幕尺寸发生变化
if (layoutRequested) {
//
final Resources res = mView.getContext().getResources();
if (mFirst) {
// make sure touch mode code executes by setting cached value
// to opposite of the added touch mode.
mAttachInfo.mInTouchMode = !mAddedTouchMode;
ensureTouchModeLocally(mAddedTouchMode);
} else {
// 这里mOverscanInsets,mContentInsets, mStableInsets
// 低版本使用的是ContentInset, 6.0以后换成OverScanInset
// 在全屏状态下的window,利用inset来布局屏幕内部
if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
insetsChanged = true;
}
if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
insetsChanged = true;
}
if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
insetsChanged = true;
}
if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) {
insetsChanged = true;
}
if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
}
if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
insetsChanged = true;
}
if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) {
insetsChanged = true;
}
// 如果Activity的layoutparam被设置成AT_MOST模式时,
// 意思是Activity窗口的大小要等于内容区域的大小, //但是Activity的大小要覆盖屏幕,所以Activity的宽高设置成当前屏幕的宽高
// 这也意味着屏Activity窗口发生变化
if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
windowSizeMayChange = true;
if (shouldUseDisplaySize(lp)) {
Point size = new Point();
mDisplay.getRealSize(size);
desiredWindowWidth = size.x;
desiredWindowHeight = size.y;
} else {
Configuration config = res.getConfiguration();
desiredWindowWidth = dipToPx(config.screenWidthDp);
desiredWindowHeight = dipToPx(config.screenHeightDp);
}
}
}
// 3. 按照view的tree结构进行递归测量
windowSizeMayChange |= measureHierarchy(host, lp, res,
desiredWindowWidth, desiredWindowHeight);
// 4。 layout
if (didLayout) {
performLayout(lp, mWidth, mHeight);
}
// 5. 调用relayoutWindow 通过请求WMS来计算Activity穿欧的大小以及扫边区域inset大小,并且保存在mWinFrame中
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
// 没有取消绘制以及没有新创建的surface
if (!cancelDraw && !newSurface) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
// 6. 执行draw操作
performDraw();
} else {
if (isViewVisible) {
// 重新来计算
scheduleTraversals();
} else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).endChangingAnimations();
}
mPendingTransitions.clear();
}
}
}
}
view Measure 测量流程
private void measureHierarchy(){
boolean goodMeasure = false;
//。。。正常情况下不会发生
if(!goodMeasure){
childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
// 执行测量
// MATCH_PARENT --> exactly
// WRAP_CONTENT --> at_most
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
privoid void performMeasure(){
// 注意这里实际调用到是View.java#measure方法
DecorView.measure(childWSpec, childHSpec);
}
```
View.java
```
public findal void measure(int wSpec, int hSpec){
// layout 模式, LAYOUT_MODE_CLIP_BOUNDS,LAYOUT_MODE_OPTICAL_BOUNDS,
// 默认是LAYOUT_MODE_OPTICAL_BOUNDS,所以一般这个地方为false
boolean optical = isLayoutModeOptical(this);
if (optical != isLayoutModeOptical(mParent)) {
// 如果当前的View的layoutMode与父mode不一致的情况下, 如果是option, 则减去insets, 否则+option
Insets insets = getOpticalInsets();
int oWidth = insets.left + insets.right;
int oHeight = insets.top + insets.bottom;
widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth);
heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);
}
// 压缩成一个long, 高32 + 低32
long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
// 在被调用了requestlayou时会设置forceLayout
final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
// 优化,对于exactl参数
final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec
|| heightMeasureSpec != mOldHeightMeasureSpec;
final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
&& MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec)
&& getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);
final boolean needsLayout = specChanged
&& (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize);
if (forceLayout || needsLayout) {
// 清除
mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
resolveRtlPropertiesIfNeeded();
int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasureCache) {
// 当cache里面没有缓存数的时候,以当前的值继续计算
onMeasure(widthMeasureSpec, heightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} else {
// 有缓存的时候直利用缓存,避免每次都要调用onmeasure方法
long value = mMeasureCache.valueAt(cacheIndex);
// Casting a long to int drops the high 32 bits, no mask needed
setMeasuredDimensionRaw((int) (value >> 32), (int) value);
mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
// flag not set, setMeasuredDimension() was not invoked, we raise
// an exception to warn the developer
if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
throw new IllegalStateException("View with id " + getId() + ": "
+ getClass().getName() + "#onMeasure() did not set the"
+ " measured dimension by calling"
+ " setMeasuredDimension()");
}
mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
}
mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasureSpec = heightMeasureSpec;
// 缓存保存上一次数据, 这里的缓存会在requestlayout的时候缓存清除
mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
(long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
}
protect coid onMeasure(...){
// 保存测量的w和h到mMeasuredWidth,mMeasureHeight
setMeasureDimension(getDefaultSize(......), getDefualtSize(.....))
}
```
ViewGroup.java
```
protect void
protected void measureChildren(in wSpec, int hSpec){
}
protect void measureChild(int wSpec, int hSpec){
}
protect void measureChildWithMargins(View child, ....){
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
// 根据父view的限定以及自身的限定计算宽高
// getChildMeasureSpec 是一个static方法
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+ heightUsed, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
// 1. 分离父view的mode, size
// 2. 计算当前父view的剩余空间size-padding
// 3. 结合父view的限定以及子view的layout参数,计算子view的测量mode以及最大size
// 3.1 父view是EXACTLY(match_parent/ xxdpi)
1) 子view childDimension >0, view模式为EXACTLY, size为childDimesion
2)子view 是MATCH_PARENT, 对应view是EXACTLY, size为剩余空间的size, 子view设置成父view的大小
3) 子view WRAP_CONTENT 对应view是AT_MOST, size为剩余空间的size, 子view的最大的大小不能超过父view
// 3.2 父view是AT_MOST(wrap_content) 依赖子view
1) 子view 是childDimession,对应是EXACTLY, size 为childDimesion
2)子view 是MATCH_PARENT, 对应view是AT_MOST, size为剩余空间的size
3) 子view WRAP_CONTENT 对应view是AT_MOST, size为剩余空间的size
// 3.2 父view是UNSPECIFIED(wrap_content) 依赖子view
1) 子view 是childDimession,对应是EXACTLY, size 为childDimesion
2)子view 是MATCH_PARENT, 对应view是UNSPECIFIED, size为剩余空间的size
3) 子view WRAP_CONTENT 对应view是UNSPECIFIED, size为剩余空间的size
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
```
LinearLayout.java
```
void measureVertical(int wSpec, int hSpec){
// 1. 计算子view的高度
count = getChildCount();
for(int i = 0; i < count; i ++){
// 剔除掉null, 和gone的view
if(weight方式设置高度[height = 0;weight>] 且高度固定){
mTotalLenghth = mTotalLength + lp.toMargin + lp.bottomMargin;
}else{
if(heigth = 0 && weight >0){
oldHeight = 0;
lp.height = WRAP_CONTNET;
}
}
// 计算child的宽高以及mode
measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
heightMeasureSpec, usedHeight);
// 累加计算整体高度
final int totalLength = mTotalLength;
mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
lp.bottomMargin + getNextLocationOffset(child));
// 只有当当前allFillParent 为true, 且为Exactly。,,
allFillParent = allFillParent && lp.width == LayoutParams.MATCH_PARENT;
if (lp.weight > 0) {
weightedMaxWidth = Math.max(weightedMaxWidth,
matchWidthLocally ? margin : measuredWidth);
} else {
alternativeMaxWidth = Math.max(alternativeMaxWidth,
matchWidthLocally ? margin : measuredWidth);
}
}
// 2. 计算LinearLayout 总高度高度
// 这里useLargestChild为true,表示使用最大的子View的高度来作为自己的高度
// 这个view赋值 只在
if (useLargestChild &&
(heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
mTotalLength = 0;
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
}
if (child.getVisibility() == GONE) {
i += getChildrenSkipCount(child, i);
continue;
}
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
child.getLayoutParams();
// Account for negative margins
final int totalLength = mTotalLength;
mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +
lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));
}
}
// 累加padding
mTotalLength += mPaddingTop + mPaddingBottom;
int heightSize = mTotalLength;
// 去最小高度和当前高度 两种的最大值
heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
// 将size和mode 赋值
int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
// 3. 换算weight, 重新计算view
int delta = heightSize -mTotalLength;
if(delta != 0 && totalWeight > 0){
float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
for(int i =0; i < count ; i ++){
// 遍历子view
float childExtra = lp.weight;
int share = (int) (childExtra * delta / weightSum);
weightSum -= childExtra;
delta -= share;
// 重新计算height
if (mUseLargestChild && heightMode != MeasureSpec.EXACTLY) {
childHeight = largestChildHeight;
} else if (lp.height == 0 && (!mAllowInconsistentMeasurement
|| heightMode == MeasureSpec.EXACTLY)) {
// This child needs to be laid out from scratch using
// only its share of excess space.
childHeight = share;
} else {
// This child had some intrinsic height to which we
// need to add its share of excess space.
childHeight = child.getMeasuredHeight() + share;
}
// 重建更新计算
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
Math.max(0, childHeight), MeasureSpec.EXACTLY);
final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
lp.width);
child.measure(childWidthMeasureSpec, childHeightMeasureSpe
}
}
// 4. 设置计算高度以及
if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
maxWidth = alternativeMaxWidth;
}
maxWidth += mPaddingLeft + mPaddingRight;
// Check against our minimum width
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
heightSizeAndState);
if (matchWidth) {
forceUniformWidth(count, heightMeasureSpec);
}
}
```
#### View layout 流程
view.java
```
public void layout(int l, int t, int r, int b) {
if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
// 是否需要在layout之前重新测量,在测量的时候缓存中存在的时候
onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}
// 暂存上一次的layout结果
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
// 根据layout模式,设置viwe的四个顶点的位置, 并根据以前的值判断是否发生变化
// return (mLeft != left || mRight != right || mTop != top || mBottom != bottom)
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
// 在发生变化了,或者有layout请求的时候重新layout
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
// 重写时候的核心方法
onLayout(changed, l, t, r, b);
if (shouldDrawRoundScrollbar()) {
if(mRoundScrollbarRenderer == null) {
mRoundScrollbarRenderer = new RoundScrollbarRenderer(this);
}
} else {
mRoundScrollbarRenderer = null;
}
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
// layout的系统回调
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);
}
}
}
final boolean wasLayoutValid = isLayoutValid();
mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
// 省略。。。
}
```
对于onLayout的方法实现,以下以FrameLayout作为例子
FrameLayout.java
```
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// 最终实现部分是layoutChildren
layoutChildren(left, top, right, bottom, false);
}
void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
final int count = getChildCount();
// 计算出父view的layout参数,left,right,top,bottom
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) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
int childLeft;
int childTop;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = DEFAULT_CHILD_GRAVITY;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
// 水平计算
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
// Gravity 参数的作用在于Layout阶段,根据这个参数来计算child的位置
case Gravity.CENTER_HORIZONTAL:
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
if (!forceLeftGravity) {
childLeft = parentRight - width - lp.rightMargin;
break;
}
case Gravity.LEFT:
default:
childLeft = parentLeft + lp.leftMargin;
}
// 垂直计算
switch (verticalGravity) {
case Gravity.TOP:
childTop = parentTop + lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = parentBottom - height - lp.bottomMargin;
break;
default:
childTop = parentTop + lp.topMargin;
}
// 递归下去
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
```
#### view Draw流程
ViewRootImpl.java
```
private void performDraw() {
try {
boolean canUseAsync = draw(fullRedrawNeeded);
if (usingAsyncReport && !canUseAsync) {
mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);
usingAsyncReport = false;
}
} finally {
mIsDrawing = false;
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
// 核心
private boolean draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (!surface.isValid()) {
return false;
}
// 获取mDirty,需要重新绘制的区域
final Rect dirty = mDirty;
if (mSurfaceHolder != null) {
dirty.setEmpty();
if (animating && mScroller != null) {
mScroller.abortAnimation();
}
return false;
}
// 第一次绘制流程需要绘制所有的区域
if (fullRedrawNeeded) {
mAttachInfo.mIgnoreDirtyState = true;
dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
}
mAttachInfo.mDrawingTime =
mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
boolean useAsyncReport = false;
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
// If accessibility focus moved, always invalidate the root.
boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
mInvalidateRootRequested = false;
// Draw with hardware renderer.
mIsAnimating = false;
if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
mHardwareYOffset = yOffset;
mHardwareXOffset = xOffset;
invalidateRoot = true;
}
if (invalidateRoot) {
mAttachInfo.mThreadedRenderer.invalidateRoot();
}
dirty.setEmpty();
// Stage the content drawn size now. It will be transferred to the renderer
// shortly before the draw commands get send to the renderer.
final boolean updated = updateContentDrawBounds();
if (mReportNextDraw) {
// report next draw overrides setStopped()
// This value is re-sync'd to the value of mStopped
// in the handling of mReportNextDraw post-draw.
mAttachInfo.mThreadedRenderer.setStopped(false);
}
} else {
// 核心方法,
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
scalingRequired, dirty, surfaceInsets)) {
return false;
}
}
}
}
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
final Canvas canvas;
int dirtyXOffset = xoff;
int dirtyYOffset = yoff;
if (surfaceInsets != null) {
dirtyXOffset += surfaceInsets.left;
dirtyYOffset += surfaceInsets.top;
}
try {
dirty.offset(-dirtyXOffset, -dirtyYOffset);
final int left = dirty.left;
final int top = dirty.top;
final int right = dirty.right;
final int bottom = dirty.bottom;
//锁定绘制区域
canvas = mSurface.lockCanvas(dirty);
// The dirty rectangle can be modified by Surface.lockCanvas()
//noinspection ConstantConditions
if (left != dirty.left || top != dirty.top || right != dirty.right
|| bottom != dirty.bottom) {
attachInfo.mIgnoreDirtyState = true;
}
d
canvas.setDensity(mDensity);
} catch (Surface.OutOfResourcesException e) {
handleOutOfResourcesException(e);
return false;
} catch (IllegalArgumentException e) {
Log.e(mTag, "Could not lock surface", e);
mLayoutRequested = true; // ask wm for a new surface next time.
return false;
} finally {
dirty.offset(dirtyXOffset, dirtyYOffset); // Reset to the original value.
}
try {
try {
canvas.translate(-xoff, -yoff);
if (mTranslator != null) {
mTranslator.translateCanvas(canvas);
}
canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
attachInfo.mSetIgnoreDirtyState = false;
# 此处mView 为decorView, 最终调用View.java##draw方法
mView.draw(canvas);
drawAccessibilityFocusedDrawableIfNeeded(canvas);
} finally {
if (!attachInfo.mSetIgnoreDirtyState) {
// Only clear the flag if it was not set during the mView.draw() call
attachInfo.mIgnoreDirtyState = false;
}
}
}
return true;
```
View.java 回到draw方中去
```
public void draw(Canvas canvas) {
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
// 按照顺序
// 1. Draw the background
// 2. 保存当前图层信息不一定执行)
// 3. 绘制view 内容,通过调用onDraw
// 4. dispatchDraw, 绘制子view
// 5. 绘制View fade的便于,类似阴影小姑
// 6. 绘制View装饰物,例如滚动条
// 1. 绘制背景
if (!dirtyOpaque) {
drawBackground(canvas);
}
// 2,保存状态
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// 3. 绘制内容, 自定义View绘制
if (!dirtyOpaque) onDraw(canvas);
// 4. 绘制子view
dispatchDraw(canvas);
drawAutofilledHighlight(canvas);
// Overlay is part of the content and draws beneath Foreground
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// Step 6, 绘制装饰物
onDrawForeground(canvas);
return;
}
}
```
ViewGroup 绘制子View
```
protected void dispatchDraw(Canvas canvas) {
boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
final int childrenCount = mChildrenCount;
final View[] children = mChildren;
int flags = mGroupFlags;
// 遍历调用子view
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;
}
}
}
}
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
// 子view draw方
return child.draw(canvas, this, drawingTime);
}
```
最终会调用子view 的draw方法
```
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
//省略...
if (!drawingWithDrawingCache) {
if (drawingWithRenderNode) {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
((DisplayListCanvas) canvas).drawRenderNode(renderNode);
} else {
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
dispatchDraw(canvas);
} else {
draw(canvas);
}
}
} else if (cache != null) {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
if (layerType == LAYER_TYPE_NONE) {
// no layer paint, use temporary paint to draw bitmap
Paint cachePaint = parent.mCachePaint;
if (cachePaint == null) {
cachePaint = new Paint();
cachePaint.setDither(false);
parent.mCachePaint = cachePaint;
}
cachePaint.setAlpha((int) (alpha * 255));
canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
} else {
// use layer paint to draw the bitmap, merging the two alphas, but also restore
int layerPaintAlpha = mLayerPaint.getAlpha();
mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha));
canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint);
mLayerPaint.setAlpha(layerPaintAlpha);
}
}
}
```
网友评论