| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Android 自定义View总结(2) -> 正文阅读 |
|
[移动开发]Android 自定义View总结(2) |
说到那些炫酷的自定义View,就离不开动画。 属性动画和硬件加速属性动画ViewPropertyAnimator1.使用View.animate()创建对象,以及使用ViewPropertyAnimator.translationX()等方法来设置动画; 2.可以连续调用来设置多个动画; 3.可以用setDuration()来设置持续时间; 4.可以用setStartDelay()来设置开始延时; ObjectAnimator使用ObjectAnimator.ofxxx()来创建对象,以及使用ObjectAnimator.statr()来主动启动动画。它的优势在于,可以为自定义属性设置动画。
另外,自定义属性需要设置?getter?和?setter?方法,并且?setter?方法里需要调用 来触发重绘:
可以使用 setduration()来设置持续时间; 可以用 setStartDelay()来设置开始延时; 以及其他一些便捷方法。 Interpolator插值?,用于设置时间完成度到动画完成度的计算公式,直白地说即设置动画的速度曲线,通过setInterpolator(Interpolator)方法来设置. 常用的有 AccelerateDecelerateInterpolator:开始与结束的地方速率改变比较慢,在中间的时候加速 AccelerateInterpolator:开始的地方速率改变比较慢,然后开始加速 DecelerateInterpolator:在开始的地方快然后慢 LinearInterpolator:?以常量速率改变 PropertyValuesHolder 用于设置更加详细的动画,例如多个属性应用于同一个对象:
或者,配合使用 ,对一个属性分多个段:
AnimatorSet?将多个 Animator 合并在一起使用,先后顺序或并列顺序都可以:
?TypeEvaluator 用于设置动画完成度到属性具体值的计算公式。默认的offInt()和ofFloat()已经有了自带的IntEvaluator和FloatEvaluator,但有的时候需要自己设置 Evaluator。例如,对于颜色,需要为 int 类型的颜色设置 ArgbEvaluator,而不是让它们使用 IntEvaluator:
? 硬件加速硬件加速是什么1.使用 CPU 绘制到 Bitmap,然后把 Bitmap 贴到屏幕,就是软件绘制; 2.使用 CPU?把绘制内容转换成 GPU?操作,交给 GPU,由 GPU?负责真正的绘制,就叫硬件绘制; 3.使用 GPU 绘制就叫做硬件加速 怎么就加速了??1.GPU 分摊了工作 2.GPU 绘制简单图形(例如方形、圆形、直线)在硬件设计上具有先天优势,会更快 ?3.流程得到优化(重绘流程涉及的内容更少) 硬件加速的缺陷:兼容性。由于使用 GPU 的绘制(暂时)无法完成某些绘制,因此对于一些特定的 API,需要关闭硬件加速来转回到使用 CPU 进行绘制。 离屏缓冲:1.离屏缓冲是什么:单独的一个绘制 View(或 View 的一部分)的区域 2.setLayerType() 和 saveLayer() 2.setLayerType() 是对整个 View,不能针对 onDraw() 里面的某一具体过程 3.这个方法常用来关闭硬件加速,但它的定位和定义都不只是一个「硬件加速开关」。 ?它的作用是为绘制设置一个离屏缓冲,让后面的绘制都单独写在这个离屏缓冲内。如果参数填写LAYER_TYPE_SOFTWARE,会把离屏缓冲设置为一个 Bitmap ,即使用软件绘制来进行缓冲,这样就导致在设置离屏缓冲的同时,将硬件加速关闭了。但需要知道,这个方法被用来关闭硬件加速,只是因为 Android?并没有提供一个便捷的方法在 View?级别简单地开关硬件加速而已。 4.saveLayer() 是针对 Canvas 的,所以在 onDraw() 里可以使用 saveLayer() 来圈出具体哪部分绘制要用离屏缓冲 5.然而……最新的文档表示这个方法太重了,能不用就别用,尽量用 setLayerType()?代替。 自定义布局布局过程1.确定每个 View?的位置和尺寸 作用:为绘制和触摸范围做支持 ?2.绘制:知道往哪里绘制 ?3.触摸反馈:知道用户点的是哪里 流程1.从整体看: 测量流程:从根 View 递归调用每一级子 View 的 measure() 方法,对它们进行测量 布局流程:从根 View 递归调用每一级子 View 的 layout() 方法,把测量过程得出的子 View的位置和尺寸传给子 View,子 View?保存 2.从个体看,对于每个 View:
具体开发继承已有的 View,简单改写它们的尺寸:SquareImageView
对自定义 View 完全进行自定义尺寸计算:重写 onMeasure():CircleView
3.1resolveSize() / resolveSizeAndState() 内部实现 3.1.1首先用 MeasureSpec.getMode(measureSpec) 和MeasureSpec.getSize(measureSpec) 取出父 对自己的尺寸限制类型和具体限制尺寸; 3.1.2如果 measure spec 的 mode 是 EXACTLY,表示父 View 对子 View 的尺寸做出了精确限制,所以就放弃计算出的 size,直接选用 measure spec 的 size; 3.1.3如果 measure spec 的 mode 是 AT_MOST,表示父 View 对子 View 的尺寸只限制了上限,需要看情况: (1)如果计算出的 size 不大于 spec 中限制的 size,表示尺寸没有超出限制,所以选用计算出的 size; (2)而如果计算出的 size 大于 spec 中限制的 size,表示尺寸超限了,所以选用spec 的 size,并且在 resolveSizeAndState() 中会添加标志MEASURED_STATE_TOO_SMALL(这个标志可以辅助父 View 做测量和布局的计算; (3)如果 measure spec 的 mode 是 UNSPECIFIED,表示父 View 对子 View 没有任何尺寸限制,所以直接选用计算出的 size,忽略 spec 中的 size。 3.1.4使用 setMeasuredDimension(width, height)?保存结果
? 自定义 Layout:重写 onMeasure() 和 onLayout():TagLayout1.重写onMeasure()(1)遍历每个子 View,用 measureChildWidthMargins()?测量子 View (2)需要重写 generateLayoutParams() 并返回 MarginLayoutParams 才能measureChildWithMargins() 方法 (3)有些子 View 可能需要重新测量(比如换行处) (4)测量完成后,得出子 View 的实际位置和尺寸,并暂时保存
?2.重写 onLayout()
自我测量,那么同样由于自己的可用空间和自己的两个 MeasureSpec?有关,所以也需要根据自己的 widthMeasureSpec?和 heightMeasureSpec 中的 mode?来分情况判断:
测量出所有子 View?的位置和尺寸后,计算出自己的尺寸,并用setMeasuredDimension(width, height) 保存? 最后重写 onLayout()遍历每个子 View,调用它们的 layout() 方法来将位置和尺寸传给它们:完整代码
触摸反馈基础自定义单 View 的触摸反馈重写 onTouchEvent(),在方法内部定制触摸反馈算法(1)是否消费事件取决于 ACTION_DOWN 事件是否返回 true (2)MotionEvent 2.1 getActionMasked() 和 getAction() 2.2 POINTER_DOWN / POINTER_UP 和 getActionIndex() ? ? ? ?View.onTouchEvent()(1)当用户按下(ACTION_DOWN): 如果不在滑动控件中,切换至按下状态,并注册长按计时? ; 如果在滑动控件中,切换至预按下状态,并注册按下计时? (2)当进入按下状态并移动(ACTION_MOVE): 重绘 Ripple E?ect;? 如果移动出自己的范围,自我标记本次事件失效,忽略后续事件 (3)当用户抬起(ACTION_UP): 如果是按下状态并且未触发长按,切换至抬起状态并触发点击事件,并清除一切状态 ;如果已经触发长按,切换至抬起状态并清除一切状态 当事件意外结束(ACTION_CANCEL): 切换至抬起状态,并清除一切状态 自定义 ViewGroup 的触摸反馈(1)除 了 重 写 onTouchEvent() , 还 需 要 重 写 onInterceptTouchEvent() (2)onInterceptTouchEvent() 不用在第一时间返回 true,而是在任意事件,需要拦截的时候返回true 就行 触摸反馈的流程? View.dispatchTouchEvent()1.如果设置了 OnTouchListener,调用 OnTouchListener.onTouch() (1)如果 OnTouchListener 消费了事件,返回 true (2)如果 OnTouchListener 没有消费事件,继续调用自己的 onTouchEvent(),并返回和onTouchEvent() 相同的结果 2.如果没有设置 OnTouchListener,同上 ViewGroup.dispatchTouchEvent()1.如果是用户初次按下(ACTION_DOWN),清空 TouchTargets 和 DISALLOW_INTERCEPT ?标记拦截处理 2.如果不拦截并且不是 CANCEL 事件,并且是 DOWN 或者 POINTER_DOWN,尝试把pointer(手指)通过 TouchTarget 分配给子 View;并且如果分配给了新的子 View,调用child.dispatchTouchEvent() 把事件传给子 View 3.看有没有 TouchTarget (1)如果没有,调用自己的 super.dispatchTouchEvent() (2)如果有,调用 child.dispatchTouchEvent()?把事件传给对应的子 View(如果有的话) 4.如果是 POINTER_UP,从 TouchTargets?中清除 POINTER?信息,如果是 UP??或 CANCEL,重置状态 TouchTarget作用:记录每个子 View 是被哪些 pointer(手指) 按下的结构:单向链表 拦截处理1.如果不是初次按下,并且没有 TouchTarget,直接拦截 2.如果是初次按下,或者有 TouchTarget (1)如果设置了 disallow intercept,不拦截 (2)否则,调用 onInterceptTouchEvent(),如果返回 true 则拦截,返回 false 则不拦截 ? |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 | -2025/1/31 5:48:38- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |