美文网首页
android源码之View绘制

android源码之View绘制

作者: jackynew2019 | 来源:发表于2019-04-09 08:18 被阅读0次

    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()

    1. requestLayout
    2. requestFocus
    3. 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);
            }
        }
    
    }
    ```

    相关文章

      网友评论

          本文标题:android源码之View绘制

          本文链接:https://www.haomeiwen.com/subject/emjviqtx.html