SurfaceView->SurfaceView基本概念

news2024/11/8 12:05:05

绘制过程

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()
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1819243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

李宏毅深度学习01——基本概念简介

视频链接 基本概念 Regression&#xff08;回归&#xff09;&#xff1a; 类似于填空 Classification&#xff08;分类&#xff09;&#xff1a; 类似于选择 Structure Learning&#xff08;机器学习&#xff09;&#xff1a; &#xff1f;&#xff1f; 机器学习找对应函数…

媲美Sora,免费使用!带物理模拟的,文生视频模型

6月13日&#xff0c;知名3D建模平台Luma AI发布最新文生视频模型Dream Machine&#xff0c;向所有用户免费开放使用。 Dream Machine除了支持文本之外&#xff0c;还可使用图片作为引导来生成视频&#xff0c;其生成的视频质量、动作一致性、色彩、光影、饱和度、运镜等方面&a…

CentOS系统自带Python2无法使用pip命令

Linux运维工具-ywtool 目录 一. 系统环境二.解决三.验证四.备注(1)输入"yum install -y python-pip",提示没有可用 python-pip包(2)安装完pip后进行升级 一. 系统环境 centos7系统自带的python2.7无法使用pip命令 二.解决 yum install python-pip -y三.验证 pip…

【QT5】<知识点> QT串口编程

目录 前言 一、串口编程步骤 0. 添加串口模块 1. 自动搜索已连接的串口 2. 创建串口对象 3. 初始化串口 4. 打开串口 5. 关闭串口 6. 发送数据 7. 接收数据 二、简易串口助手 1. 实现效果 2. 程序源码 3. 实现效果二 前言 本篇记录QT串口编程相关内容&#xff0…

Yolo-World训练过程中使用wandb进行可视化

训练过程可视化有两种方式&#xff1a;wandb和tensorboard&#xff0c;这里我采用的是wandb&#xff0c;想要在训练过程中调用wandb只需要在要训练的配置文件&#xff08;如yolo_world_v2_l_vlpan_bn_sgd_1e-3_40e_8gpus_finetune_coco.py&#xff09;中加上一行代码即可&#…

k8s+springboot+redis部署配置连接

1 springboot 配置k8s中的redis服务名 #tomcat访问端口 # 应用名称 spring.application.namedemo # 应用服务Web访问端口 server.port8089 server.envtest #缓存关闭 spring.thymeleaf.cachefalse #可选配置 management.endpoints.enabled-by-defaulttrue management.endpoint…

SpringBoot接入RS-232串口通讯实现数据交互

目录 一、什么是RS-232&#xff1f; 先看看硬件通讯接口长啥样 RS-232 二、方案一 1.前期准备 a.配置 RXTX 1&#xff09;下载 RXTX 包并解压 2&#xff09;拷贝动态库到对应的jdk目录下 Windows平台 Linux平台 3&#xff09;在工程根目录下创建 lib 文件夹&#x…

提升网络安全韧性:从基础防护开始

随着信息技术的迅猛发展&#xff0c;互联网已深刻融入社会的各个层面&#xff0c;从日常生活到企业运营&#xff0c;再到国家基础设施。与此同时&#xff0c;网络威胁和攻击也呈现出多样化和复杂化的趋势&#xff0c;给网络安全带来了严峻挑战。 一、背景 随着信息技术的迅猛发…

力扣每日一题 6/13 反悔贪心算法

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 2813.子序列最大优雅度【困难】 题目&#xff1a; 给你一个长度为 n 的二…

使用pyqt对yolov5进行简答部署

YOLOv5是一种高效的实时目标检测算法&#xff0c;广泛应用于各类计算机视觉任务中。为了实现便捷的图形用户界面&#xff08;GUI&#xff09;&#xff0c;我们采用了PyQt框架。PyQt是一个Python绑定的Qt库&#xff0c;用于创建跨平台的应用程序。 在本研究中&#xff0c;我们首…

LINUX网络FTP服务

一、FTP服务 FTP服务&#xff1a;file transfer protocol :文件传输协议。在网络上进行双向传输&#xff0c;也是一个应用程序。不同的操作系统有不同的FTP软件&#xff0c;但使用的协议是一样的。 FTP协议基于TCP协议&#xff0c;有两个端口&#xff0c;即20和21。 20端口&…

GTX的64B66B编码(高速收发器十九)

点击进入高速收发器系列文章导航界面 前文讲解了8B10B的原理&#xff0c;8B10B的开销比较大&#xff0c;每传输10位数据&#xff0c;就需要发送2位无效数据。为了减小8B10B编码的开销&#xff0c;同时保留编码方案的优点&#xff0c;提出了64B66B编码。 64B66B编码与8B10B编码方…

批量记录收支明细,轻松掌握财务动向,查看并统计上个月收支明细

在这个快节奏的时代&#xff0c;财务管理已经成为我们生活中不可或缺的一部分。然而&#xff0c;面对繁琐的收支明细记录&#xff0c;很多人感到头痛不已。今天&#xff0c;我们为您推荐一款高效的财务管理工具——晨曦记账本&#xff0c;让您轻松实现批量记录收支明细&#xf…

HTML|01HTML初识

HTML初识 1.html标签&#xff1a;所有html中标签的一个根节点 2.head标签&#xff1a;用于存放&#xff1a;title,meta,base,style,script,link 3.title标签&#xff1a;显示网站标题 4.body标签&#xff1a;显示主体 HTML骨架语法 <html> <head> <title>…

数据防泄密知识集锦|5个有效防止数据泄露的方法,你知道吗?

以下是五个有效防止数据泄露的方法&#xff0c;它们涵盖了从加强员工意识到技术实施等多个方面。 1.部署数据安全防护系统&#xff1a;安企神软件 专业的企业数据防泄密软件能够全方位地保护企业数据的安全。 该系统通常具有强大的文件加密功能、实时监控和异常检测、灵活的权…

使用 PNPM 从零搭建 Monorepo,测试组件并发布

1 目标 通过 PNPM 创建一个 monorepo&#xff08;多个项目在一个代码仓库&#xff09;项目&#xff0c;形成一个通用的仓库模板。 这里以在该 monorepo 项目中搭建 web components 类型的组件库为例&#xff0c;介绍从仓库搭建、组件测试到组件发布的整个流程。 这个仓库既可…

eclipse 老的s2sh(Struts2+Spring+Hibernate) 项目 用import导入直接导致死机(CPU100%)的解决

1、下载Apache Tomcat - Apache Tomcat 8 Software Downloads 图中是8.5.100的版本&#xff0c;下面的设置用的是另一个版本的&#xff0c;其实是一样。 2、先将Server配好&#xff0c;然后再进行导入操作。 2、选择jdk 当然&#xff0c;这里也可以直接“Download and instal…

Vue指令的使用以及自定义指令

文章目录 1. 指令概述2.常用指令的分类2.1 内容渲染指令2.1.1 v-text2.1.2 插值语法{{ }}2.1.2.1 插值语法{{}}可以写什么2.1.2.2 插值语法可以解决什么 2.1.3 v-html 2.2 属性绑定指令(v-bind)2.3 事件绑定指令(v-on)2.4 双向绑定指令(v-model)2.4.1 v-bind和v-model的区别和联…

【Java】解决Java报错:IllegalStateException during HTTP Request

文章目录 引言一、IllegalStateException的定义与概述1. 什么是IllegalStateException&#xff1f;2. IllegalStateException在HTTP请求中的常见触发场景3. 示例代码 二、解决方案1. 确保响应只被提交一次2. 正确管理Servlet的生命周期3. 避免重复访问输入流和输出流4. 使用框架…

光储充行业市场前景以及未来发展趋势

光储充行业作为新能源汽车产业链的重要环节&#xff0c;其市场前景广阔&#xff0c;未来发展趋势也呈现出积极向上的态势。随着新能源汽车市场的不断扩大&#xff0c;光储充设施的需求也日益增长&#xff0c;为行业的发展提供了强大的动力。 从未来发展趋势来看&#xff0c;光储…