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]

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

被折叠的 条评论
为什么被折叠?



