1、SurfaceView是什么?
首先SurfaceView本身也是一个View。SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。一般来说,你能看到的一个窗口就是一个Surface,大概可以理解为一个Activity创建出一个可视化界面,而这个界面就可以理解为一个Surface,Activity在这个Surface上不断绘制,从而看到Android上的界面。Surface是纵深排序(Z-ordered)的,它总在自己所在窗口的后面surfaceview提供了一个可见区域,只有在这个可见区域内 的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。
2、为啥要用SurfaceView?
surfaceview的核心在于提供了两个线程:UI线程和渲染线程。如果用View本身来绘制,效率不高。
SurfaceView的UI就可以在一个独立的线程中进行绘制,可以不会占用主线程资源,还有就是SurfaceView使用了双缓冲机制,双缓冲机制的原理就是可以看成两个canvas,一个用于前台显示,另外一个用于储存前台上一次显示的画布,你所操作的都是在第二个canvas上面进行,进行完了之后再替换为新的canvas,这样重复的交替绘制来渲染,使整个画面会更加的流畅。
3、如何使用SurfaceView?
先初始化布局,新建一个activity,在布局里面申明SurfaceView.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<SurfaceView
android:id="@+id/mSurfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>获得SurfaceHolder对象,然后给SurfaceHolder对象设置回调监听。客户端可以实现实现SurfaceHolder.Callback接口来接收有关Surface变化。Callback接口里面一共有surfaceCreated、surfaceChanged、surfaceDestroyed这三个方法。
/**
* A client may implement this interface to receive information about
* changes to the surface. When used with a {@link SurfaceView}, the
* Surface being held is only available between calls to
* {@link #surfaceCreated(SurfaceHolder)} and
* {@link #surfaceDestroyed(SurfaceHolder)}. The Callback is set with
* {@link SurfaceHolder#addCallback SurfaceHolder.addCallback} method.
*/
public interface Callback {
/**
* This is called immediately after the surface is first created.
* Implementations of this should start up whatever rendering code
* they desire. Note that only one thread can ever draw into
* a {@link Surface}, so you should not draw into the Surface here
* if your normal rendering will be in another thread.
*
* @param holder The SurfaceHolder whose surface is being created.
*/
//大概意思是讲当surface第一次被创建的时候会立马回调这个方法,可以在这里初始化一些你所需要的东西渲染代码。
//而需要注意的是只有一条线程可以在surface上绘制,想渲染绘制应该是在其他的线程。您的正常渲染将在另一个线程中
public void surfaceCreated(SurfaceHolder holder);
/**
* This is called immediately after any structural changes (format or
* size) have been made to the surface. You should at this point update
* the imagery in the surface. This method is always called at least
* once, after {@link #surfaceCreated}.
*
* @param holder The SurfaceHolder whose surface has changed.
* @param format The new PixelFormat of the surface.
* @param width The new width of the surface.
* @param height The new height of the surface.
*/
//作用于surface在任何结构(格式或者尺寸)的变化,都会立马回调这个方法。就是在这个点去更新图像。
//这个方法总是至少被调用一次。换句话说就是可能会被调用多次。
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height);
/**
* This is called immediately before a surface is being destroyed. After
* returning from this call, you should no longer try to access this
* surface. If you have a rendering thread that directly accesses
* the surface, you must ensure that thread is no longer touching the
* Surface before returning from this function.
*
* @param holder The SurfaceHolder whose surface is being destroyed.
*/
//当surface即将销毁的时候,会立马回调此方法。在这个时候你应该过多的再去使用Surface。
//如果你有一个正在执行渲染的线程。当这个方法返回之前,你应该确保这个线程再也不会去接触这个Surface了
public void surfaceDestroyed(SurfaceHolder holder);
}绘制我们res的一张图片上去。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mSurfaceView.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder?) {
Thread {
if (holder != null) {
//初始化画笔
var mypaint = Paint()
//抗锯齿
mypaint.isAntiAlias = true
//锁定画布
var canvas = holder.lockCanvas()
//获取一张图片
var bitmap =BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher_round)
if (bitmap != null) {
//在画布上把图片绘制上去
canvas.drawBitmap(bitmap, Matrix(), mypaint)
}
//解锁画布
holder.unlockCanvasAndPost(canvas)
}
}.start()
}
override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) {
}
override fun surfaceDestroyed(holder: SurfaceHolder?) {
}
})
}
}一张图片就显示出来了,这种方式是用surface来绘制的。这只是入门级的,哈哈。