SurfaceView源码分析

本文深入解析了SurfaceView的工作原理及绘制机制,详细介绍了其构造方法、onMeasure、onLayout及关键方法updateSurface的具体实现,同时提供了示例代码帮助理解。

SV继承自View,但是并不是利用View的Draw来进行绘制。而是直接跟SurfaceFlinger进行通信。那么看下具体SV是怎么实现这个功能的,它的用法如何?
还是先从构造方法开始看起。

  public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
   
   
        super(context, attrs, defStyleAttr, defStyleRes);
        //Enable callbacks for position changes. 
        mRenderNode.requestPositionUpdates(this);
        //此方法规定不会走正常的draw方法。
        setWillNotDraw(true);
    }

假设我们直接贴一个SurfaceView 到布局中,给SV一定宽高,SV会形成一个"黑洞"区域。如图。
在这里插入图片描述

在这里插入图片描述

现在来分析下这是如何形成的。
由于SV也是一个View,只是绘制的时候会走自己的绘制机制。对于常规的onMesure和onLayout还是一样会跑的。这个也是SV得以能够进行绘制的前提条件,因为你必须首先有大小,然后有位置,其次才是在具体位置利用画笔(paint)进行绘制的。那么先来看看onMeasure。


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   
   
    //mRequestedWidth 由setFixedSize设置,默认情况是-1。那么默认是走getDefaultSize.也就是基本的测量方法。
        int width = mRequestedWidth >= 0
                ? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
                : getDefaultSize(0, widthMeasureSpec);
        int height = mRequestedHeight >= 0
                ? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
                : getDefaultSize(0, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

所以onMeasure可以说平平无奇。
接下来看下布局。发现SV并没有重写这个onLayout方法。但是有重写setFrame方法,这个方法是View中,layout过程调用的。所以布局的时候必然会走到这个setFrame方法。

/** @hide */
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
   
   
    boolean result = super.setFrame(left, top, right, bottom);
    updateSurface();
    return result;
}

这里面的关键方法就是updateSurface方法.

    /** @hide */
    protected void updateSurface() {
   
   
    //判断是否有长宽。经历了measure之后mHaveFrame为true.
        if (!mHaveFrame) {
   
   
            return;
        }
        //获取View 根。
        ViewRootImpl viewRoot = getViewRootImpl();
        //主要看最后一个就是说View的mSurface是否准备完毕。也就是说,必须ViewTree的surface准备完毕才会走到后面的方法。正常流程经历了onResume,surface准备完毕,才会发起requestlayout,才会有布局的。
        if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
   
   
            return;
        }
 // mTranslator 属于一个转换器。   
        mTranslator = viewRoot.mTranslator;
        if (mTranslator != null) {
   
   
            mSurface.setCompatibilityTranslator(mTranslator);
        }

        int myWidth = mRequestedWidth;
        if (myWidth <= 0) myWidth = getWidth();
        int myHeight = mRequestedHeight;
        if (myHeight <= 0) myHeight = getHeight();

        final boolean formatChanged = mFormat != mRequestedFormat;
        final boolean visibleChanged = mVisible != mRequestedVisible;
        //判断Surface是否正在创建状态,但是没有创建完毕。从这里也可以看到SF的surface和ViewRoot的surfcace并不是同一个。
        final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
                && mRequestedVisible;
        final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
        final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
        boolean redrawNeeded = false;
        
        if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
   
   
        //获取sf控件在其整个屏幕上的坐标位置,并且存储在mLocation中。
            getLocationInWindow(mLocation);
            try {
   
   
                final boolean visible = mVisible = mRequestedVisible;
                mWindowSpaceLeft = mLocation[0]
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值