1.SurfaceView概述
SurfaceView从Android 1.0(API level 1)时就有 。它继承自类View,因此它本质上是一个View。但与普通View不同的是,它有自己的Surface,这个Surface在WMS中有自己对应的WindowState,在SF中也会有自己的Layer。
也就是说,虽然在App端它仍在View hierachy中,但在Server端(WMS和SF),它与宿主窗口是分离的。这样的好处是对这个Surface的渲染可以放到单独线程去做,渲染时可以有自己的GL context。这对于一些游戏、视频等性能相关的应用非常有益,因为它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用。
SurfaceView属于View的子类它是专门为制作游戏而产生的,它的功能非常强大,最重要的是它支持OpenGL ES库,2D和3D的效果都可以实现。创建SurfaceView的时候需要实现SurfaceHolder.Callback接口,它可以用来监听SurfaceView的状态,比如:SurfaceView的改变 、SurfaceView的创建 、SurfaceView 销毁等。
SurfaceView、SurfaceHolder、Surface的关系可以概括为以下几点:
- SurfaceView是拥有独立绘图层的特殊View。
- Surface就是指SurfaceView所拥有的那个绘图层,其实它就是内存中的一段绘图缓冲区。
- SurfaceView中具有两个Surface,也就是我们所说的双缓冲机制
- SurfaceHolder顾名思义就是Surface的持有者,SurfaceView就是通过过SurfaceHolder来对Surface进行管理控制的。并且SurfaceView.getHolder方法可以获取SurfaceView相应的SurfaceHolder。
- Surface是在SurfaceView所在的Window可见的时候创建的。我们可以使用SurfaceHolder.addCallback方法来监听Surface的创建与销毁的事件。
2.SurfaceView使用
下面,我们用SurfaceView来显示一张图片。
代码示例:
public class HdrPictureSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Canvas mCanvas;
private Paint mPaint;
private Paint mFontPaint;
private Rect mSrcRect;
private Rect mDstRect;
private static Integer mHeight;
private static Integer mWidth;
private static Context mContext;
public HdrPictureSurfaceView(Context context) {
this(context, null);
}
public HdrPictureSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
try (TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.HdrPictureSurfaceView)) {
mIsHardwareAccel = attributes.getBoolean(R.styleable.HdrPictureSurfaceView_isHardwareAccel, false);
}
mContext = context;
init();
}
private void init() {
mHolder = getHolder();
mHolder.setFormat(PixelFormat.RGBA_F16);
mHolder.addCallback(this);
mSrcRect = new Rect();
mDstRect = new Rect();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//创建画笔
mFontPaint = new Paint();
mFontPaint.setStyle(Paint.Style.FILL);
mFontPaint.setColor(Color.CYAN);
mFontPaint.setStrokeWidth(12);
mFontPaint.setTextSize(50);
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mWidth = wm.getDefaultDisplay().getWidth();
mHeight = wm.getDefaultDisplay().getHeight();
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
drawImage();
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged");
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed");
}
protected void drawImage() {
Log.i(TAG, "drawImage...");
Bitmap bitmap;
synchronized (mLock) {
bitmap = mBitmaps.get(mBitmapIndex); //根据实际情况由image获取
}
if (mIsHardwareAccel) {
mCanvas = mHolder.lockHardwareCanvas();
} else {
mCanvas = mHolder.lockCanvas();
}
boolean hardwareAccelerated = mCanvas.isHardwareAccelerated();
Log.i(TAG, "drawImage(): hardwareAccelerated=" + hardwareAccelerated);
if (mCanvas != null) {
mCanvas.drawColor(Color.BLACK);
mSrcRect.set(0, 100, bitmap.getWidth(), bitmap.getHeight());
mDstRect.set(0, 100, mWidth, bitmap.getHeight() * mWidth / bitmap.getWidth());
mCanvas.drawBitmap(bitmap, mSrcRect, mDstRect, mPaint);//将bitmap画到画布上
}
if (mIsHardwareAccel) {
mCanvas.drawText("硬件加速Canvas", 0.f, 50.f, mFontPaint);
} else {
mCanvas.drawText("普通Canvas", 0.f, 50.f, mFontPaint);
}
mHolder.unlockCanvasAndPost(mCanvas);//解锁画布同时提交
}
}