这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战
前言
前几天在看自定义View的一些东西,然后突然脑子冒出来一个东西,很早之前自己写的一个播放器,用的是Android自带的视频播放器,还用的MediaPlayer + surfaceView,纯简单的播放,暂停,没有任何业务,但是后来发现业务堆砌上来后,满足不了了,就换了封装好的vitamio,然后一直用了1年多吧,最后公司发展,用了百度的播放器了,一直没更换过了,当然这只是个经历,想说的就是我也用过surfaceView,哈哈
SurfaceView 和 View 的区别
其实简单的说就是一个是在主线程刷新,一个是在子线程中刷新UI
View在UI线程去更新自己;
SurfaceView则在一个子线程中去更新自己
SurfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面在UI的主线程中更新动画,时间一旦太长就会出现问题
SurfaceView在新的线程中更新画面所以不会阻塞你的UI主线程,但是涉及到线程同步,需要SurfaceView中 thread处理.
举个栗子:
我们自己手动的点击事件,触发的动画用View,需要一直动一直刷新的动画用surfaceView
SurfaceView的使用
需要创建一个新的扩展了SurfaceView的类,并实现SurfaceHolder.Callback
class MySurfaceView : SurfaceView, SurfaceHolder.Callback, Runnable {
constructor(context: Context?) : this(context, null)
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
override fun surfaceCreated(p0: SurfaceHolder) {
Log.e("surfaceCreated", "surfaceCreated")
}
override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) {
Log.e("surfaceChanged", "surfaceChanged")
}
override fun surfaceDestroyed(p0: SurfaceHolder) {
Log.e("surfaceDestroyed", "surfaceDestroyed")
}
}
用法很简单,下面写一个手绘签名得了栗子:
class MySurfaceView : SurfaceView, SurfaceHolder.Callback, Runnable {
private var mSurfaceHolder: SurfaceHolder? = null
//绘图的Canvas
private var mCanvas: Canvas? = null
//子线程标志位
private var mIsDrawing = false
private var mPaint: Paint? = null
private var mPath: Path? = null
private var bitmap: Bitmap? = null
constructor(context: Context?) : this(context, null)
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
mPaint = Paint()
mPaint?.setColor(Color.BLACK)
mPaint?.setStyle(Paint.Style.STROKE)
mPaint?.setAntiAlias(true)
mPaint?.setStrokeWidth(5f)
mPath = Path()
//路径起始点(0, 100)
//路径起始点(0, 100)
mPath?.moveTo(0f, 100f)
initView()
}
/**
* 初始化View
*/
private fun initView() {
mSurfaceHolder = holder
mSurfaceHolder?.addCallback(this)
isFocusable = true
keepScreenOn = true
isFocusableInTouchMode = true
}
override fun surfaceCreated(p0: SurfaceHolder) {
mIsDrawing = true
Thread(this).start()
}
override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) {
Log.e("surfaceChanged", "surfaceChanged")
}
override fun surfaceDestroyed(p0: SurfaceHolder) {
mIsDrawing = false
}
override fun run() {
while (mIsDrawing) {
drawSomething()
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
val x = event.x.toInt()
val y = event.y.toInt()
when (event.action) {
MotionEvent.ACTION_DOWN -> {
Thread.sleep(10)
mPath!!.moveTo(x.toFloat(), y.toFloat())
}
MotionEvent.ACTION_MOVE -> mPath!!.lineTo(x.toFloat(), y.toFloat())
MotionEvent.ACTION_UP -> {
}
}
return true
}
/***
* 处理画布事件
*/
private fun drawSomething() {
try {
//获得canvas对象
mCanvas = mSurfaceHolder!!.lockCanvas()
//绘制背景
mCanvas?.drawColor(Color.WHITE)
//绘制路径
mCanvas?.drawPath(mPath!!, mPaint!!)
} catch (e: Exception) {
} finally {
if (mCanvas != null) {
//释放canvas对象并提交画布
mSurfaceHolder!!.unlockCanvasAndPost(mCanvas)
}
}
}
/***
* 清除画布内容
*/
fun clearContent() {
mSurfaceHolder!!.addCallback(this)
mPath = Path()
}
/***
* 获取画布内容,并返回bitmap对象
*/
fun getImage(): Bitmap {
bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
var mCanvas = Canvas(bitmap!!)
mCanvas?.drawColor(Color.WHITE)
mCanvas?.drawPath(mPath!!, mPaint!!)
return bitmap!!
}
}
总结
拿起来,放下去,再拿起来,感觉还是很好,能自己想写点什么就写点什么,哪怕是记录一个时间点,也是很好的,以后看看,原来我在这里还留下了点东西,一起学习吧