绘制过程
View和SurfaceView绘制过程

PhoneWindow:Window的具体实现,在Activity中调用setContentView()方法时,一个PhoneWindow实例会对应一个ViewRootImpl实例,绘制,事件分发传递给ViewRootImpl进行ViewRootImpl:View树绘制的根节点,自顶向下绘制- 普通
View绘制:ViewRootImpl会调用View.draw(Canvas canvas)方法在Canvas对象上进行绘制,绘制完成后将绘制结果(一张Bitmap),最终交给SurfaceFlinger进行合成和显示 SurfaceView绘制:在绘制开始时,SurfaceView会通过SurfaceHolder.lockCanvas()方法来获取并锁定Canvas,然后在Canvas上进行绘制。通过SurfaceHolder.unlockCanvasAndPost()方法将绘制的内容提交到自己的Surface上,最终交给SurfaceFlinger进行合成和显示。SurfaceView是用来展示Surface数据的地方,用来控制整个Surface中绘制内容的位置和大小
- 普通
Surface:每一个Surface对应了一块屏幕缓冲区,包含了显示到屏幕的绘制内容
View和SurfaceView的区别
-
绘制线程:普通
View是在主线程绘制的,而SurfaceView可以在子线程绘制。当绘制操作非常复杂,普通View可能会阻塞主线程,SurfaceView可以避免UI变得不流畅。 -
重绘方式:普通
View需要更新时,整个View树都需要重新绘制。而SurfaceView可以只更新自身的内容,而不影响到其他的View -
Z轴顺序:
SurfaceView的Surface则默认位于其所在窗口的背景之上、其他普通View之下 -
透明度:普通
View可以设置任意的透明度,而SurfaceView则只能是完全透明或者完全不透明。 -
综上所述,
View适合用于构建常规的用户界面,而SurfaceView则更适合用于需要频繁更新并且绘制操作复杂的场景,比如视频播放、游戏等
XML文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cardview_dark_background"
tools:context=".MainActivity"
android:orientation="vertical">
<com.example.drag.MySurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
自定义SurfaceView代码
class MySurfaceView(context: Context) : SurfaceView(context), SurfaceHolder.Callback, Runnable {
private val TIME_IN_FRAME = 30L
private var isDrawing = false
private var drawThread: Thread? = null
private var mCanvas: Canvas? = null
private var mPath = Path()
private val mPaint = Paint().apply {
color = Color.WHITE
strokeWidth = 5f
style = Paint.Style.STROKE
}
init {
holder.addCallback(this)
isFocusable = true // 键盘事件获取焦点
isFocusableInTouchMode = true // 触摸事件获取焦点
keepScreenOn = true // 屏幕常亮
}
constructor(context: Context, attrs: AttributeSet) : this(context)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : this(context)
override fun onTouchEvent(event: MotionEvent): Boolean {
val x = event.x
val y = event.y
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
mPath.moveTo(x, y)
}
MotionEvent.ACTION_MOVE -> {
mPath.lineTo(x, y)
}
MotionEvent.ACTION_UP -> {
// mPath.reset() 会导致刷新闪烁
}
}
return true
}
override fun surfaceCreated(holder: SurfaceHolder) {
// 初始化操作,例如加载资源或设置画布
isDrawing = true
drawThread = Thread(this).apply { start() }
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
// 处理 Surface 尺寸变化的逻辑
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
// 释放资源,停止线程等清理操作
isDrawing = false
}
private fun draw() {
try {
synchronized(holder) {
mCanvas = holder.lockCanvas()
// mCanvas?.drawColor(Color.BLACK) 清空画布
// 获取Canvas对象开始绘制
mCanvas?.drawPath(mPath, mPaint)
}
} catch (e: Exception) {
Log.e(TAG, Log.getStackTraceString(e))
} finally {
if (mCanvas != null) {
// 绘制内容提交给Surface
holder.unlockCanvasAndPost(mCanvas)
}
}
}
override fun run() {
while (isDrawing) {
var startTime = System.currentTimeMillis()
draw()
var endTime = System.currentTimeMillis()
while ((endTime-startTime) < TIME_IN_FRAME) {
// 没有达到绘制帧间隔时间,线程等待
Thread.sleep(TIME_IN_FRAME - (endTime - startTime))
endTime = System.currentTimeMillis()
}
}
}
}



















