SurfaceView->SurfaceView基本概念

绘制过程

ViewSurfaceView绘制过程

在这里插入图片描述

  • PhoneWindowWindow的具体实现,在Activity中调用setContentView()方法时,一个PhoneWindow实例会对应一个ViewRootImpl实例,绘制,事件分发传递给ViewRootImpl进行
  • ViewRootImplView树绘制的根节点,自顶向下绘制
    • 普通View绘制:ViewRootImpl会调用View.draw(Canvas canvas)方法在Canvas对象上进行绘制,绘制完成后将绘制结果(一张Bitmap),最终交给SurfaceFlinger进行合成和显示
    • SurfaceView绘制:在绘制开始时,SurfaceView会通过SurfaceHolder.lockCanvas()方法来获取并锁定Canvas,然后在Canvas上进行绘制。通过SurfaceHolder.unlockCanvasAndPost()方法将绘制的内容提交到自己的Surface上,最终交给SurfaceFlinger进行合成和显示。SurfaceView是用来展示 Surface 数据的地方,用来控制整个 Surface 中绘制内容的位置和大小
  • Surface:每一个Surface 对应了一块屏幕缓冲区,包含了显示到屏幕的绘制内容

ViewSurfaceView的区别

  • 绘制线程:普通View是在主线程绘制的,而SurfaceView可以在子线程绘制。当绘制操作非常复杂,普通View可能会阻塞主线程,SurfaceView可以避免UI变得不流畅。

  • 重绘方式:普通View需要更新时,整个View树都需要重新绘制。而SurfaceView可以只更新自身的内容,而不影响到其他的View

  • Z轴顺序:SurfaceViewSurface则默认位于其所在窗口的背景之上、其他普通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()
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值