View绘制

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 嵌套滑动

 

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关于项目时间与数据库中的时间不一致问题(少8个小时)

关于项目情况: 1.springboot项目 2.数据库为MySQL 3.数据库时间正常,与实际时间一致. 4.项目获取到的时间比数据库的时间少八个小时 原因是没有给日期格式设置时区,导致其变为世界时,比北京时间少八个小时 在application.yml 配置文件中添加时区属性; 配置文件路径 spri…

【复位与释放(亚稳态)模为60的BCD码计数器_2023.11.22】

复位与释放&#xff08;异步复位&#xff0c;同步释放&#xff09; 同步复位rst、同步置数load&#xff08;置数信号只有在时钟上升沿到来时才能生效&#xff09;、同步清零clr 同步复位&#xff1a; always(posedge clk) if(!rst_n) b<1’b0; else b<a; 同步复位信号rs…

〔005〕虚幻 UE5 像素流多用户部署

✨ 目录 ▷ 为什么要部署多用户▷ 开启分发服务器▷ 配置启动多个信令服务器▷ 配置启动客户端▷ 多用户启动整体流程和预览▷ 注意事项 ▷ 为什么要部署多用户 之前的像素流部署&#xff0c;属于单用户&#xff0c;是有很大的弊端的打开多个窗口访问&#xff0c;可以看到当一…

Linux 命令pwd

命令作用 pwd是Linux中一个非常有用而又十分简单的命令&#xff0c;pwd是词组print working directory的首字母缩写&#xff0c;即打印工作目录&#xff1b;工作目录就是你当前所处于的那个目录。 pwd始终以绝对路径的方式打印工作目录&#xff0c;即从根目录&#xff08;/&am…

百度地图JavaScript API GL获取经纬度,标记,添加文本标注,点击事件,封装

百度地图JavaScript API GL常用方法封装 引入百度js库 <script type"text/javascript" src"https://api.map.baidu.com/api?v1.0&typewebgl&ak自己的百度应用ak"></script>封装方法 <template><div class"map"&…

Vue3生命周期函数(简述题)

1.图示 2.说明 3.补充 1.在vue3组合式API中&#xff0c;我们需要将生命周期函数先导入&#xff0c;然后才能使用。 import {onMounted} from vue2.beforeCreate和created被setup()方法所代替

CTO对生活和工作一点感悟

陌生人&#xff0c;你好啊。 感谢CSDN平台让我们有了隔空认识&#xff0c;交流的机会。 我是谁&#xff1f; 我呢&#xff0c;毕业快11年&#xff0c;在网易做了几年云计算&#xff0c;后来追风赶上了大数据的浪潮&#xff0c;再到后来混迹在AI、智能推荐等领域。 因为有一颗…

增加F110 付款方式的随手记录

随便记录一下&#xff0c;基本上有这些信息可以了 为了保持PRD与测试机一致的银行代码&#xff0c;需要先在DEV&#xff0c;QAS 改成4 外部给号 主要都是在FBZP 开户行维护-FI12_HBANK/FI12 S4hana 里面有的没有办法在FI12 维护只能去NWBC NWBC&#xff1a;维护银行账户并关联…

软件测试简历怎么写?可以参考这份简历

个人简历 基本信息 姓名&#xff1a;名字 性别&#xff1a;男 年龄&#xff1a;25 学历&#xff1a;本科 联系电话&#xff1a…

C++: string的模拟实现

C: string的模拟实现 一.前置说明1.模拟实现string容器的目的2.我们要实现的大致框架 二.默认成员函数1.构造函数2.拷贝构造函数1.传统写法2.现代写法 3.析构函数4.赋值运算符重载1.传统写法2.现代写法 三.遍历和访问1.operator[]运算符重载2.iterator迭代器 四.容量相关函数1.…

【Vue3+Vite】解决build后空白页的问题

目录 Hash 模式 HTML5 模式&#xff08;历史模式&#xff09; 配置Nginx 配置Spring Boot Hash 模式 build后空白页的问题可能是使用的是历史模式&#xff0c;因为Vue是一个单页的客户端应用&#xff0c;如果没有适当的服务器配置&#xff0c;访问会得到一个 404 错误…

智慧水务系统在流域水环境规划中起到什么作用?

智慧水务系统在流域水环境规划中扮演着越来越重要的角色。作为一款集信息化、自动化、智能化、智慧化于一体的水务管理系统&#xff0c;智慧水务系统不仅能够提高水环境规划的效率&#xff0c;还能为水资源的保护和利用提供有力支持。 在流域水环境规划中&#xff0c;智慧水务系…

计算机硬件(一)

1.机箱 计算机的许多硬件,如主板,硬盘和电源等,都安放在固定机箱中。机箱是一个相对封闭的空间&#xff0c;箱体一般由钢和铝合金等金属制成(其他材料亦可用&#xff0c;但不多见),同时设有许多通风口,以促进箱内空气流动,防止内部温度过高&#xff0c;机箱的颜色,大小乃至形状…

c++ 中名空间中using 引入的细节

如果在引入名空间中的特定成员函数的时候&#xff0c; 全局不能定义同名的函数&#xff0c;但是其实只要参数不同就行 namespace a{int x 1;int fun(){return 0;} }using namespace a; using a::fun;void fun(int x) {} int x 10; int main() {fun(10); } 上面就是一个正确…

TZOJ 1378 发工资咯

答案&#xff1a; #include<stdio.h> int main() {int n 0, m 0, i 0, sum 0;while (scanf("%d", &n) && n ! 0) //多组数据输入并且不等于0{for (i 0; i < n; i) //有n名老师就循环n次{scanf("%d", &m); //该名老…

rabbitMQ对消息不可达处理-备份交换机/备份队列

生产者发送消息&#xff0c;在消息不可达指定队列时&#xff0c;可以借助扇出类型交换机&#xff08;之前写过消息回退的处理方案&#xff0c;扇出交换机处理的方案优先级高于消息回退&#xff09;处理不可达消息&#xff0c;然后放置一个备份队列&#xff0c;供消费者处理不可…

解压压缩包脚本

解压压缩包脚本 我们一般解压一个压缩包&#xff0c;需要三步&#xff1a; 1、打开压缩包。 2、点击解压文件。 3、选择解压目录解压到指定文件夹。 那么&#xff0c;怎么一步完成这些繁琐的操作呢&#xff1f;编写一个bat脚本即可&#xff0c;如下所示&#xff1a; 1、安装解压…

【人工智能Ⅰ】实验5:AI实验箱应用之贝叶斯

实验5 AI实验箱应用之贝叶斯 一、实验目的 1. 用实验箱的摄像头拍摄方块上数字的图片&#xff0c;在图像处理的基础上&#xff0c;应用贝叶斯方法识别图像中的数字并进行分类。 二、实验内容和步骤 1. 应用实验箱机械手臂上的摄像头拍摄图像&#xff1b; 2. Opencv处理图像…

Wish防关联是什么?Wish要怎样避免违规封店?

四大跨境电商平台之一wish&#xff0c;做跨境电商的很多人可能都听过wish。随着wish不断完善平台制度&#xff0c;对于多账号运营的卖家要求越来越严厉&#xff0c;wish和亚马逊、eBay等其它跨境电商平台一样&#xff0c;不支持一个卖家开设多个账号多家店铺。 但是对于各位卖家…

2023/11/24JAVAweb学习(Vue常用指令,Vue.js文件,Ajax,Axios两种请求,Vue-cli脚手架,Vue项目,Element)

age只会执行成立的,show其实都展示了,通过display不展示 使用Vue,必须引入Vue.js文件 假如运行报错,以管理员身份打开vscode,再运行 ------------------------------------------------------------------- 更改端口号