美文网首页
Android View的绘制简单分析四

Android View的绘制简单分析四

作者: 梧叶已秋声 | 来源:发表于2020-12-22 11:18 被阅读0次

以下代码皆为伪代码,并不能实际显示View,忽略了很多细节,目的是为了方便日后回顾结构。

public class ViewRootImpl {
    boolean mFullRedrawNeeded;
    public final Surface mSurface = new Surface();
    int mWidth;
    int mHeight;
    Rect mDirty;
    private View mView;

    public ViewRootImpl(){
        mWidth = -1;
        mHeight = -1;
        mDirty = new Rect();
    }

    public void setView(View view) {
        if (mView == null) {
            mView = view;
        }
    }

    void doTraversal() {
        mWidth = 100;
        mHeight = 100;
        mDirty.set(0, 0, mWidth, mHeight);

        performTraversals();
    }

    private void performTraversals() {
        mDirty.set(0, 0, mWidth, mHeight);
        performDraw();
    }

    //为了减少代码量所以一律改成void
    private void performDraw() {
        final boolean fullRedrawNeeded = mFullRedrawNeeded;
        draw(fullRedrawNeeded);
    }

    private void draw(boolean fullRedrawNeeded) {
        Surface surface = mSurface;
        final Rect dirty = mDirty;
        drawSoftware(surface,dirty);


    }

    /**
     * @return true if drawing was successful, false if an error occurred
     */
    private boolean drawSoftware(Surface surface,Rect dirty) {

        // Draw with software renderer.
        final Canvas canvas;
        canvas = mSurface.lockCanvas(dirty);
        mView.draw(canvas);

        return true;
    }
}
public class View {
    public int mPrivateFlags;
    static final int PFLAG_SKIP_DRAW                   = 0x00000080;
    static final int PFLAG_DIRTY_MASK                  = 0x00200000;

    public View(Context context) {
     }


    public void draw(Canvas canvas) {
        // Step 3, draw the content
        onDraw(canvas);

        // Step 4, draw the children
        dispatchDraw(canvas);

    }


    protected void onDraw(Canvas canvas) {

    }

 
    boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
        // Fast path for layouts with no backgrounds
        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
            //PFLAG_SKIP_DRAW = 1000 0000
            //如果mPrivateFlags = 1000 0000
            // 也就是说,如果此时如果mPrivateFlags为1000 0000,也就是调用draw(Canvas canvas, ViewGroup parent, long drawingTime)的View不需要绘制
            // 那么就调用dispatchDraw,绘制调用draw(Canvas canvas, ViewGroup parent, long drawingTime)的View的children。
            // 这里Flags 暂不深入,什么时候mPrivateFlags = 1000 0000,当前调用draw的View为ViewGroup的时候吗?需在framework中加tag去测试。
            //取反0111 1111
            //1000 0000
            //0111 1111
            //mPrivateFlags = 0000 0000,执行dispatchDraw。
            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
            dispatchDraw(canvas);
        } else {
            //反之则调用draw(canvas),绘制自身。
            draw(canvas);
        }

        return false;
    }

    protected void dispatchDraw(Canvas canvas) {

    }
}
public abstract class ViewGroup extends View{
    // Child views of this ViewGroup
    private View[] mChildren = new View[1];

    public ViewGroup(Context context) {
        super(context);
    }


    public void addView(View child) {
        mChildren[0] = child;

    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        int childrenCount = 1;
        final long drawingTime = 0;
        for (int i = 0; i < childrenCount; i++) {
            View child = mChildren[0];
            drawChild(canvas, child, drawingTime);
        }
    }

    protected boolean drawChild(Canvas canvas,View child, long drawingTime) {
        return child.draw(canvas, this, drawingTime);
    }

}
public class LinearLayout extends ViewGroup {
    private int mOrientation;
    public static final int HORIZONTAL = 0;
    public static final int VERTICAL = 1;
    private Drawable mDivider;

    public LinearLayout(Context context) {
        super(context);
        mOrientation = 1;
        mDivider = context.getDrawable(R.drawable.divider_vertical_bright);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mOrientation == VERTICAL) {
            drawDividersVertical(canvas);
        } else {
            drawDividersHorizontal(canvas);
        }
    }

    void drawDividersVertical(Canvas canvas) {
        drawHorizontalDivider(canvas);
    }

    void drawDividersHorizontal(Canvas canvas) {

    }

    void drawHorizontalDivider(Canvas canvas) {
        //Bounds的数值是随便定义的
        mDivider.setBounds(100, 100, 500, 500);
        mDivider.draw(canvas);
    }
}

divider_vertical_bright实际是放在framework中。但是文件可通过快速按2次shift键搜索文件得出,然后copy至工程目录下。


image.png
public class ImageView extends View{
    private Drawable mDrawable = null;

    public ImageView(Context context) {
        super(context);
        mDrawable = context.getDrawable(R.drawable.ic_launcher_background);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mDrawable.draw(canvas);
    }

}

ic_launcher_background是新建工程自带文件。

public class MainActivity extends AppCompatActivity {
    private ViewRootImpl mViewRoot;
    private LinearLayout mLinearLayout;
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewRoot = new ViewRootImpl();
        mLinearLayout = new LinearLayout(this);
        mImageView = new ImageView(this);

        mLinearLayout.addView(mImageView);
        mViewRoot.setView(mLinearLayout);
        mViewRoot.doTraversal();
    }
}

当调用mViewRoot.doTraversal()后,会调用ViewRootImpl中的drawSoftware(Surface surface,Rect dirty)。然后走到mView.draw(canvas) ,也就是mLinearLayout.draw(canvas),因为之前调用了setView(mLinearLayout)。而draw(canvas)是定义在View中供所有继承View的类使用,那么mLinearLayout.draw(canvas)会调用mLinearLayout.onDraw(canvas)mLinearLayout.dispatchDraw(canvas)
dispatchDraw(canvas)作用是draw the children,在ViewGroup中重写。

onDraw(canvas)作用是draw the contentViewGroupView中均可重写(ViewGroup中可重写,可不重写,例如LinearLayout中定义了,而FrameLayout中为重写,View中一般重写)。按实际需求来,需要改变的话,就重写。

LinearLayout调用了onDraw(canvas)后最终调用mDivider.draw(canvas);,也就是实现了mLinearLayout自身的绘制,给mLinearLayout自己绘制了个图片。
然后调用 mLinearLayout.dispatchDraw(canvas);
代码走到mImageView.draw(canvas, this, drawingTime),这里我对mPrivateFlags的赋值具体情况不太理解,但是如果不是ViewGroup的话应该是走到mImageView.draw(canvas),然后会再次调用onDraw(canvas)dispatchDraw(canvas); ,也就是mImageView.onDraw(canvas)mImageView.dispatchDraw(canvas);mImageView.dispatchDraw未重写且无具体内容,只需要看重写的mImageView.onDraw(canvas)

//ImageView
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mDrawable.draw(canvas);
    }

ImageView的onDraw定义绘制了一张图。

以上流程大致可以概括如下:
1.ViewRoot
mViewRoot.doTraversal()-->mViewRoot.performTraversals() --> mViewRoot.performDraw()--> mViewRoot.draw(fullRedrawNeeded)-->mViewRoot.drawSoftware(surface,dirty) -->
2.LinearLayout
mLinearLayout.draw(canvas)
-->mLinearLayout.onDraw(canvas)-->mLinearLayout.drawHorizontalDivider(canvas)-->mDivider.draw(canvas)
-->mLinearLayout.dispatchDraw(canvas) -->mLinearLayout.drawChild(canvas, child, drawingTime)-->
3.ImageView
mImageView.draw(canvas, this, drawingTime)-->mImageView.draw(canvas)-->mImageView.onDraw(canvas)-->mDrawable.draw(canvas)

无标题.png

参考链接:
深入理解 Android 之 View 的绘制流程(四)_Draw
Android 系统架构 —— View 的硬件渲染
Android 源码分析三 View 绘制
图解View绘制原理(软件渲染篇)
手把手教你读懂源码,View的绘制流程详细剖析
Android 源码分析 - View的measure、layout、draw三大流程
Android自定义View(三)-Draw原理篇
Android View绘制(四)onDraw过程与Canvas Bitmap
源码分析篇 - Android绘制流程(二)measure、layout、draw流程

Android中View自定义XML属性详解以及R.attr与R.styleable的区别
带你一步步了解 onDraw() 和 dispatchDraw() 的区别

View绘制体系(三)——AttributeSet与TypedArray详解
android 自定义 styleable 属性
declare-styleable的使用

Android 源码分析一 View 创建

相关文章

网友评论

      本文标题:Android View的绘制简单分析四

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