View绘制

news2024/9/21 16:27:18

onDraw 绘制

canvas 画布

paint 画笔

坐标系 x y

x 0 y 0 则屏幕左上角 y从上往下值增加

像素转换 dp2px

画线line

drawLine 

圆circle

drawCircle

drawPath:

在onSizeChanged 时候初始化

addCircle 添加圆

CW顺时针

CCW 逆时针

CW CCW填充规则不同

 填充规则:

默认 WINDING 填充 填满

EVEN_ODD  不管方向 相交点不填充

其他两个则是反方向的

path测量

画path虚线

paint.pathEffect = PathDashPathEffect()
onSizeChanged 尺寸改变时候调用

Xframe

离屏缓冲:单独拿出一块区域进行渲染

SOURSE 不仅包含图像还有底部(透明)区域

PorterDuff.Mode  |  Android Developers

  var XFERMODE = PorterDuffXfermode(PorterDuff.Mode.OVERLAY)
    var bounds = RectF(150.dp,50.dp,300.dp,200.dp)
    var paint = Paint(Paint.ANTI_ALIAS_FLAG)
    var circleBitmap = Bitmap.createBitmap(150.dp.toInt(), 150.dp.toInt(),Bitmap.Config.ARGB_8888)
    var squareBitmap = Bitmap.createBitmap(150.dp.toInt(), 150.dp.toInt(),Bitmap.Config.ARGB_8888)


    init {
        val canvas = Canvas(circleBitmap)
        paint.color = Color.parseColor("#D81B60")
        canvas.drawOval(50.dp,0.dp,150.dp,100.dp,paint)
        paint.color = Color.parseColor("#2196F3")
        canvas.setBitmap(squareBitmap)
        canvas.drawRect(0.dp,50.dp,100.dp,150.dp,paint)
    }
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onDraw(canvas: Canvas) {
        val count = canvas.saveLayer(bounds,paint)

        canvas.drawBitmap(circleBitmap,150.dp,50.dp,paint)
        paint.xfermode = XFERMODE

        canvas.drawBitmap(squareBitmap,150.dp,50.dp,paint)
        paint.xfermode = null
        canvas.restoreToCount(count)
    }

文字测量:

typeface 设置 字体

baseLine

    //设置居中
        paint.style = Paint.Style.FILL
        paint.getFontMetrics(fontMetrics)
        canvas.drawText("abab",width / 2f,height / 2f - (fontMetrics.ascent + fontMetrics.descent) / 2f ,paint)



//        paint.textAlign = Paint.Align.LEFT
//        paint.getTextBounds("abab",0,"abab".length,bonds)
//        canvas.drawText("abab",0f,-fontMetrics.ascent,paint)

        paint.textAlign = Paint.Align.LEFT
        paint.getTextBounds("abab",0,"abab".length,bonds)
        canvas.drawText("abab",-bonds.left.toFloat(),-bonds.top.toFloat(),paint)

范围裁切和几何变换

方形,左上右下  

变换View坐标系

 

坐标系放大

Camera 变换

未指定轴心:

指定轴心 移动坐标系

距离过近则图像大

后移

-8f = 8英寸  72像素 -8x72  576

camera 裁切

属性动画

animate

修改属性值

Object.Animation

单个View

tips 每次切换屏幕则执行onDraw

需要进行save 和 释放 : ondraw()

也可以使用 withSave

多个属性可以用AnimatorSet

扩展:PropertyValuesHolder

KeyFrame:

Interpolator:

加减速差值器

加速差值器

线性差值器

TypeEvaluator: 类型估值动画,每一个动画完成度的evaluator

初始值 + 动画完成度 *  剩余进度

自定义,不支持kt

ValueAnimator : 字符串动画:

硬件加速:

软绘:CPU ->软件绘制

硬绘:GPU绘制

硬件加速缺点是兼容性:

离屏缓冲 单独拿出一块区域 进行渲染 通过saveLayer开启,建议用hardware Layer

需要再onDraw方法外,执行会接着重绘

开启离屏缓冲

动画过程中临时开启硬件加速,离屏缓冲,自定义ObjectAnima不能使用,需要系统自带的动画

Bitmap / Drawable

互转

ktx 互转

源码:

bitmap 位图,像素数据 ,存储像素数据

drawable 绘制工具

默认是0 0,需要指定位置

drawble 将bitmap进行draw方法

自定义drawable

SDK 覆盖很多drawable 基本常用场景都有

自动使用起点 0f

obtainStyledAttributes int 数组,把不属于这个view的属性过滤

然后根据序列号取值

自定义写法:

布局流程:

确定子View相对于父View的位置

流程

可能会测量多次

1.第一次测量

2.第二次测量

多次测量,不确定大小

取最大的

流程2

LinearLayout 不会修正子view内部的测量绘制方法,其他viewGroup 有的会修正位置比如ConstraintLayout

在子onLayout时候修改位置尺寸,则父View不会修改

view 会这只l t r b 位置,进行保存

自定义尺寸:

子view的layout是父view传过来的宽高尺寸信息

getWidth getHeight 父View测量的尺寸 = r-l    b-t

计算自己测量的尺寸,然后保存结果传给父view

子View修正宽高

//        //修正 宽度
//        val speceMode = MeasureSpec.getMode(widthMeasureSpec)
//        val speceSize = MeasureSpec.getSize(widthMeasureSpec)
//        val width = when(speceMode){
//            MeasureSpec.EXACTLY -> speceSize
//            MeasureSpec.AT_MOST -> if (size > speceSize) speceSize else size
//            MeasureSpec.UNSPECIFIED -> size
//        }
//
//        //修正高度
//        val speceHeightMode = MeasureSpec.getMode(heightMeasureSpec)
//        val speceHeightSize = MeasureSpec.getSize(heightMeasureSpec)
//        val height = when(speceHeightMode){
//            MeasureSpec.EXACTLY -> speceHeightSize
//            MeasureSpec.AT_MOST -> if (size > speceHeightSize) speceHeightSize else size
//            MeasureSpec.UNSPECIFIED -> size
//        }
//等同于 resolveSize resolveSizeAndState

resolveSizeAndState 会传一个SMALL 传给父view 重新测量

但是一般父view不会读to small

resolveSize
val width = resolveSize(size,widthMeasureSpec)
val height = resolveSize(size,heightMeasureSpec)
setMeasuredDimension(width, height)

自定义Layout

取layoutparams会得到marginLayoutParams 

 

需要重写方法

View 绘制流程

子线程更新UI

onCreate 不会报错

点击事件

不会报错,如果用wrap_content 则会报错

如果调用requestLayout 则不会报错

不会报错

报错则会触发checkThread

所有的view都会往上调用requestLayout,传递,然后触发检查机制

onResume之后可能也没完成测绘流程

Activity 包含一个mWindow对象,mWindow在

Activity的OnCreate在ActivityThread中的  - handleCreateActivity , onStart ,onResume 也是在类似的方法调用

Activity对象创建也是在ActivityThread中创建

然后调用

通过classLoader 实例化Activity

创建出然后调用attch

然后调用onCreate

attch方法之后调用onCreate

然后创建mWindow = PhoneWindow

setContentView 则是在调用window.setContentView

phoneWindow 包含Decor

关联

PhoneWindow -- localFeatures特征

写在setContentView前调用,设置window属性

替换不同的布局 NO_TITLE = 

布局

 

源码findViewById  则会调用decorview的findViewByid

installDecor

创建Decor 然后添加contentView

创建布局然后添加到Parent

ViewRootImpl

子线程更新UI报错栈

如果Partnet = null 则不会触发checkThread

mThread

创建ViewRootImpl 时 创建Thread

ViewRootImpl由  创建

Activity CallActivityResume

windowmanager 是个接口

windowmangerglobal 是个单例对象

然后找到viewrootimpl

SurfaceView则不会执行这样的流程

触摸反馈:

 true 消费事件 不在传递

点击事件

TooLTP  辅助事件

down 设置longclick  延时器

setProssed 设置为按下按下状态

每次滑动都会等待一定时间

500ms = longclick,TapTime = 100

调用先后关系

View 多点触控

单点触控 拖拽View,记录当前按下的位置和偏移量,下一次移动时加上偏移量= 现在按下的位置

触摸事件 是针对view的 每次事件是个序列,会有id,index x , y

getX 获取的是序号0,第一根手指的X

源码:

通过getX(index) 获取指定手指的坐标系

获取当前按下手指的坐标

双指移动view 判断是哪根手指 然后进行取值

 配合型 计算焦点和差值

ViewGroup 触控:

mesaureChildren 给所有的子View一个统一的宽和高

遍历子view 指定位置 从左上角开始设置为填满

当自定义的ViewGroup是个滑动控件,如果拦截子View,返回true之外,还需要通知父View不再拦截

需要自己处理

如果滑动内层view 父view会收到拦截事件,子View会收到Touchevnent

外层则子View收不到消息

scrollTo View的方法,往上则会是负向滑动,是反方向设置

velocityTancker 速度记录器,惯性滑动

滑动速度变量,最小/最大/滑动速度,先初始化,然后clear

然后做计算,参数为单位和上限,1000则表示每秒移动的速度

给定一个位置,然后让其内部计算,然后最终值为0,切换更线性

通过scrollTo和postAnimation 会调用draw方法

滑动startScroll 和postInvalidateOnAnimation 成对调用

mesaureChildren 测量子View,规定其大小

 拖拽:

onDragListener

开始拖拽 startDrag,data,只有等松手时才能取到

拖拽监听器

布局加载完成,每个view都设置监听器,拖拽其中一个,其他的都会收到回调

外接式拖拽监听:跟onDragListener不相关

dragCallback:

当View被拖拽时 ,显示在上方

当View坐标改变

当View放下

完成滑动后自动计算并且重排

startDragAndDrop,判断支持哪种方式进行拖拽

设置监听器:

回调

支持跨进程回调,松手时数据才会被调用

上下滑动拖拽

ScrollView 嵌套滑动

 

实现接口,然后重写嵌套滑动事件逻辑

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

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

相关文章

NX二次开发UF_MTX2_vec_multiply_t 函数介绍

文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan UF_MTX2_vec_multiply_t Defined in: uf_mtx.h void UF_MTX2_vec_multiply_t(const double vec [ 2 ] , const double mtx [ 4 ] , double vec_product [ 2 ] ) overview 概述 Ret…

邮政快递物流查询,将指定某天签收的单号筛选出来

批量查询邮政快递单号的物流信息,将指定某天签收的单号筛选出来。 所需工具: 一个【快递批量查询高手】软件 邮政快递单号若干 操作步骤: 步骤1:运行【快递批量查询高手】软件,并登录 步骤2:点击主界面左…

python-nmap库使用教程(Nmap网络扫描器的Python接口)(功能:主机发现、端口扫描、操作系统识别等)

文章目录 Python-nmap库使用教程前置条件引入python-nmap创建Nmap扫描实例执行简单的主机发现(nmap -sn)示例,我有一台主机配置为不响应 ICMP 请求,但使用nmap -sn,仍然能够探测到设备: 端口扫描扫描特定端…

线性回归 调试方法

调试方法 特征缩放 对于某些不具有比较性的样本特征 x i x_i xi​ (比如对其他的x来说 x i x_i xi​ 相当大或者相当小),梯度下降的过程可能会非常漫长,并且可能来回波动才能最后收敛到全局的最小值。 在这样的情况下&#xff…

SAP BW层级结构小结属性数据源+专家例程实现层级结构增强加载

作者 idan lian 如需转载备注出处 BW信息对象-层级结构 RSH1 维护信息对象层级 这里的文本描述对应T表中的描述,文本数据源加载之后有数据 信息对象层级H表 以上描述都是根据自我理解翻译的,非官方翻译 层级标识:自动生成,其实…

CCF CSP认证 历年题目自练Day50

题目 试题编号: 201809-3 试题名称: 元素选择器 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 题目分析(个人理解) 还是先理解题意,关于html的部分,可以按照样例画出…

2000-2021年各省人口密度数据

2000-2021年各省人口密度数据 1、时间:2000-2021年 2、指标:地区、年份、年末常住总人口(万人)、面积(平方千米)、人口密度(人/平方千米) 3、来源:各省年鉴、统计年鉴、各省统计局…

Redis面试题-缓存穿透,缓存击穿和缓存雪崩

目录 缓存穿透 面试官:什么是缓存穿透 ? 怎么解决 ? 面试官:你能介绍一下布隆过滤器吗? 缓存击穿 面试官:什么是缓存击穿 ? 怎么解决 ? 缓存雪崩 面试官:什么是缓存雪崩 ? 怎么解决 ? 缓存穿透 面试官&a…

笔记二十六、React中路由懒加载的扩展使用

26.1 在路由中配置懒加载 lazy routes/index.jsx 代码 import {Navigate} from "react-router-dom"; import Home from "../components/Home"; import About from "../components/About"; // import Classify from "../components/Home/c…

Vue3 刷新后,pinia存储的数据丢失怎么解决

这个问题有两种解决办法: 一是使用pinia的持久化存储一是使用vue的依赖注入 刷新后,通过pinia存储的vue store数据丢失,实际上是因为Vue原组件卸载、新组件重新挂载导致的,vue store是挂载在组件上的,当刷新导致组件…

处理机调度与作业调度

处理机调度 一个批处理型作业,从进入系统并驻留在外存的后备队列上开始,直至作业运行完毕,可能要经历如下的三级调度 高级调度 也称为作业调度、长程调度、接纳调度。调度对象是作业 主要功能: 挑选若干作业进入内存 为作业创建…

使用RobotFramework编写BDD代码

背景 行为驱动开发(Behavior Driven Development)即BDD,是一种敏捷开发方法,通常应用在自动化测试中,或者也可称为行为驱动测试。通过使用自然描述语言确定自动化脚本,通过这种方式,能够大大促…

微调Fine tune

网络架构 一个神经网络一般可以分为两块 特征抽取将原始像素变成容易线性分割的特征线性分类器来做分类 微调:使用之前已经训练好的特征抽取模块来直接使用到现有模型上,而对于线性分类器由于标号可能发生改变而不能直接使用 训练 是一个目标数据集上…

RS232串口_笔记

这里写目录标题 1、RS232串口理论起始位数据位校验位LSB & MSB示波器查看数据信号对应连接方式 1、RS232串口理论 UART(通用异步收发传输) 是一种通信协议,而 RS232 (串行通信接口)是种物理接口标准。UART 是一种用于在计算机和外部设备之间传输数据的协议&…

Mac电脑版程序创建工具 VMware InstallBuilder Enterprise mac最新

VMware InstallBuilder Enterprise 是一款功能强大、操作简单、跨平台支持的软件安装和部署工具,可以让开发者更加高效地创建和部署软件,并提供了丰富的功能和工具,适用于不同的用户需求和场景。 内置调试器 轻松排除应用程序安装过程中的故…

C语言--每日选择题--Day31

第一题 1. 下面程序 i 的值为() int main() {int i 10;int j 0;if (j 0)i; elsei--; return 0; } A:11 B:9 答案及解析 B if语句中的条件判断为赋值语句的时候,因为赋值语句的返回值是右操作数; …

NIFI源码编译部署在服务器CentOS环境中

一、下载Apache NiFi源码: Apache NiFi官网地址,文档 Apache NiFi源码GitHub地址 二、部署nifi 2.1进入opt目录,并创建software、module [rootlocalhost /]# cd /opt/ [rootlocalhost opt]# ls containerd [rootlocalhost opt]# mkdir s…

vscode-使用vscode编译和代码修改 keil工程

Visual Studio Code必要拓展(插件)安装 1. Keil Assistant 在拓展搜索栏中输入Keil,找到 Keil Assistant 点击安装下载

小航助学题库蓝桥杯题库python选拔赛(21年3月)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统(含题库答题软件账号)_程序猿下山的博客-CSDN博客 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统(含题库答题软件账号)_程序猿下山的博客-CSD…

智能遥测终端机RTU的注意事项

智能遥测终端机RTU是一种用于实时监测和控制现场数据的设备,可以广泛应用于水利、水文、电力、煤炭等各个领域。但是在使用智能遥测终端机RTU时,也需要注意一些事项,以确保终端的正常使用效果。 ◆注意安装位置   应安装在稳定、通风的室内…