自定义View之重写onMeasure
一、重写onMeasure()来修改已有的View的尺寸
步骤:
- 重写 onMeasure(),并调用 super.onMeasure() 触发原先的测量
- 用 getMeasuredWidth() 和 getMeasuredHeight() 取到之前测得的尺寸,利用这两个尺寸来计算出最终尺寸
- 使用 setMeasuredDimension() 保存尺寸
代码:
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//先执行原测量算法super.onMeasure(widthMeasureSpec, heightMeasureSpec);//获取原先的测量结果int measureWidth=getMeasuredWidth();int measureHeight=getMeasuredHeight();//利用原先的测量结果计算出新的尺寸if(measureWidth>measureHeight){measureWidth=measureHeight;}else{measureHeight=measureWidth;}//保存计算后的结果setMeasuredDimension(measureWidth,measureHeight);}
二、重写onMeasure()来全新计算自定义View的尺寸
步骤:
- 重写 onMeasure0) 把尺寸计算出来
- 把计算的结果用 resolveSize() 过滤一遍后保存
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {...measuredWidth=...;measuredHeight=...;measuredWidth=resolveSize(measuredWidth,widthMeasureSpec);measuredHeight=resolveSize(measuredHeight,heightMeasureSpec);setMeasuredDimension(measuredWidth,measuredHeight);}
onMeasure()方法的两个参数 widthMeasureSpec和heightMeasureSpec是父View对子View的尺寸限制,子View在计算自己尺寸的时候,需要遵守这两个参数所包含的限制MeasureSpec。
理解MeasureSpec:
在 Android 中,View 的大小是由父容器和 View 自身的测量规格(MeasureSpec)共同决定的。
MeasureSpec 由大小和测量模式组成,测量模式有三种取值:
-
UNSPECIFIED(未指定):父容器对子 View 没有施加任何限制,子 View 可以任意大小。
-
EXACTLY(精确):父容器已经为子 View 精确指定了大小,子 View 应该匹配这个大小。
-
AT_MOST(至多):子 View 可以是任何大小,但不能超过父容器指定的大小。
MeasureSpec 是通过静态方法 MeasureSpec.makeMeasureSpec() 创建的,该方法接受两个参数:大小和测量模式。在自定义 View 或者自定义布局中,我们通常会使用 MeasureSpec 来测量子 View 的大小,并根据测量模式来决定子 View 的大小。
在自定义 View 中,我们通常会在 onMeasure() 方法中使用 MeasureSpec 来测量 View 的大小。在这个方法中,我们可以通过 MeasureSpec.getMode() 和 MeasureSpec.getSize() 方法来获取测量模式和大小,然后根据这些信息来确定 View 的最终大小。
解释resolveSize()这个方法:
//代码简化,不是源码
public static int resolveSize(int size, int measureSpec) {final int specMode = MeasureSpec.getMode(measureSpec);final int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) {case MeasureSpec.AT_MOST:if (specSize < size) {result = specSize | MEASURED_STATE_TOO_SMALL;} else {result = size;}break;case MeasureSpec.EXACTLY:result = specSize;break;case MeasureSpec.UNSPECIFIED:default:result = size;}
}
resolveSize()这个方法,父View传进来的尺寸限制measureSpec是由类型和尺寸值组成的,首先要调用MeasureSpec.getMode(measureSpec)方法和MeasureSpec.getSize(measureSpec)方法获取限制measureSpec的类型mode和size尺寸值。
限制的类型mode:
MeasureSpec.AT_MOST 限制上线
MeasureSpec.EXACTLY 限制固定尺寸
MeasureSpec.UNSPECIFIED 无限制
三、重写onMeasure()和onLayout()来全新计算自定义ViewGroup的内部布局
onMeasure()的重写,对于ViewGroup来说,包含三部分内容:
步骤:
- 调用每个子View的measure(),让子View自我测量
- 根据子View给出的尺寸,得出子View的位置,并保存它们的位置和尺寸
- 根据子View的位置和尺寸计算出自己的尺寸,并用setMeasuredDimension()保存
理解LayoutParams
在父View里调用子View的getLayoutParams()方法,可以获得一个LayoutParams对象,它包含了xml文件里的layout_打头的参数的对应值,其中它的width和height这两个属性就分别对应了layout_width和layout_height的值,并且是转换过了的值。
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
for(int i=0;i<getChildCount();i++){View childView=getChildAt(i);LayoutParams lp=childView.getLayoutParams();//lp.height lp.width}}
结合自己的可用空间来计算出对子View的宽度和高度的限制
可以根据layout_width和layout_height的值,分成三种情况:
第一种情况:固定值
不需要考虑可用空间的问题,直接用EXACTLY把子View尺寸限制为这个固定值就可以了。
第二种情况:match_parent
把子View的尺寸限制为固定值可用宽度或者高度
可用空间的判断方法:
根据自己的MeasureSpec中mode的不同:
1.EXACTLY/AT_MOST 可用空间:MeasureSpec中的size
2.UNSPECIFIED 可用空间:无限大
第三种情况:wrap_content
不能超过父View的边界的情况下,子View自己测量
public class SomeView extends ViewGroup {
...@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {...for(int i=0;i<getChildCount();i++){View childView=getChildAt(i);LayoutParams lp=childView.getLayoutParams();int selfwidthSpecMode=MeasureSpec.getMode(widthMeasureSpec);int selfwidthSpecSize=MeasureSpec.getSize(widthMeasureSpec);switch (lp.width){case MATCH_PARENT:if(selfwidthSpecMode==EXACTLY||selfwidthSpecMode==MeasureSpec.AT_MOST){childWidthSpec=MeasureSpec.makeMeasureSpec(selfwidthSpecSize-usedWidth,EXACTLY);}else{childWidthSpec=MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);}break;case WRAP_CONTENT:if(selfwidthSpecMode==EXACTLY||selfwidthSpecMode==MeasureSpec.AT_MOST){childWidthSpec=MeasureSpec.makeMeasureSpec(selfwidthSpecSize-usedWidth,MeasureSpec.AT_MOST);}else{childWidthSpec=MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);}break;default:childWidthSpec=MeasureSpec.makeMeasureSpec(lp.width, EXACTLY);break;}}}
}
关于保存子View位置的两点说明
1.不是所有的Layout都需要保存子View的位置(因为有的Layout可以在布局阶段实时推导出子View的位置,例如LinearLayout)
2.有时候对某些子View需要重复测量两次或多次才能得到正确的尺寸和位置
重写onLayout()来摆放子View
@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {for(int i=0;i<getChildCount();i++){View childView=getChildAt(i);childView.layout(childLeft[i],childTop[i],childRight[i],childBottom[i]);}}
相关文章:

自定义View之重写onMeasure
一、重写onMeasure()来修改已有的View的尺寸 步骤: 重写 onMeasure(),并调用 super.onMeasure() 触发原先的测量用 getMeasuredWidth() 和 getMeasuredHeight() 取到之前测得的尺寸,利用这两个尺寸来计算出最终尺寸使用 setMeasuredDimensio…...

专为Mac用户设计的思维导图软件MindNode 2023 for Mac助您激发创意!
在现代快节奏的生活中,我们经常需要整理思绪、规划项目、记录灵感。而思维导图作为一种高效的思维工具,能够帮助我们更好地整理和展现思维。现在,我们介绍一款强大而直观的思维导图软件——MindNode 2023 for Mac,助您拓展思维边界…...
Linux命令——用户和权限相关
文章目录 1 用户管理1.1 用户标识符1.2 用户添加1.3 用户删除1.4 用户配置文件1.4.1 passwd文件1.4.2 shadow文件1.4.3 group文件 2 密码管理3 权限管理 1 用户管理 1.1 用户标识符 用户标识符主要是UID和GID,UID表示用户id,GID表示用户组id。在登录的…...

linux反汇编工具: ida pro、rizinorg/cutter; ubuntu 22 flameshot延迟截图 以应对下拉菜单
rizinorg/cutter rizinorg/cutter 是 命令行反汇编工具 rizinorg/rizin 的图形化界面, 这比 ida pro跑在kvm虚拟机中方便多了, ubuntu22.04下直接下载Cutter-v2.3.2-Linux-x86_64.AppImage后即可运行,如下图: 注意 有个同名的报废品: radare2/Cutter 即 radare2的图形化界…...
【INTEL(ALTERA)】使用NiosV/m 处理器,niosv-download 为什么会失败?
说明 在英特尔 Quartus Prime Pro Edition 软件 23.3 版及更高版本中将 Nios V 处理器软件下载到非流水线Nios V/m 处理器时,可能会出现此问题。 这是由于处理器限制,仅影响非流水线Nios V/m 处理器。 以下其他处理器不受此限制的影响: 管道…...

【无线通信专题】NFC通信模式及可能的应用方式
在文章【无线通信专题】NFC基本原理中我们讲到了NFC工作模式。其中NFC工作模式主要有三种,读写模式、卡模拟模式、点对点模式。 NFC通信模式丰富,NFC Forum定义了三种NFC设备:通用NFCForum设备、读写器设备和标签设备。这些NFC设备可以在三种通信模式下运行,并对应用案例进…...

pyinstaller生成的exe文件启动时间漫长的原因
加-F慢的原因是,pyinstaller把所有资源文件包括python解释器的依赖文件和库都打包到exe一个文件中,用户打开时,pyinstaller需要先执行一边解压操作,把依赖文件全部解压出来。慢就慢在这里。 如果不加-F,你会发现那些文…...
C语言基本语句介绍
c程序的执行部分是由语句组成的。程序的功能也是由执行语句来实现的,c语句分为6类 1表达式语句 表达式语句由表达式加上分号“;”组成 一般形式:表达式; 2函数调用语句 由函数名,实际参数加上分号“;”…...
【QT】QString类型中,Empty和NULL有什么区别在qt里,对比C#
在 Qt 中,QString 类型的字符串使用 isEmpty() 方法来检查字符串是否为空,而不是使用 null。这与 C# 中的 string.IsNullOrEmpty 方法略有不同。 QString::isEmpty(): 用于检查字符串是否为空。一个 QString 对象可能是空字符串,即…...

破壳而出:运维工程师在新科技热潮下的崛起与转型
运维工程师的出路到底在哪里? 在这个飞速发展的数字世界里,运维工程师无疑是IT界冲在最前线的勇士。他们曾是服务器的守护者,他们曾是故障的消灭者,他们曾是性能的推手。然而,随着科技的发展和市场需求的变化…...

静态网页设计——贵州美食(HTML+CSS+JavaScript)
前言 声明:该文章只是做技术分享,若侵权请联系我删除。!! 感谢大佬的视频: https://www.bilibili.com/video/BV1vC4y1K7de/?vd_source5f425e0074a7f92921f53ab87712357b 使用技术:HTMLCSSJS(…...

imgaug库指南(六):从入门到精通的【图像增强】之旅
引言 在深度学习和计算机视觉的世界里,数据是模型训练的基石,其质量与数量直接影响着模型的性能。然而,获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此,数据增强技术应运而生,成为了解决这一问题的…...

stable diffusion 人物高级提示词(五)场景、特效、拍摄手法、风格
一、场景 场景Promptindoor室内outdoor室外cityscape城市景色countryside乡村beach海滩forest森林mountain山脉snowfield雪原skyscraper摩天大楼ancient monument古代遗迹cathedral大教堂library图书馆museum博物馆office building办公大楼restaurant餐厅street market街头市场…...

智能分析网关V4智慧港口码头可视化视频智能监管方案
一、需求背景 近年来,水利港口码头正在进行智能化建设,现场管理已经是重中之重。港口作为货物、集装箱堆放及中转机构,具有昼夜不歇、天气多变、环境恶劣等特性,安全保卫工作显得更加重要。港口码头的巡检现场如何高效、快捷地对…...

docker部署kibana
1,简介 官网 kibana 2,安装docker 参考 linux安装docker 3,准备 Kibana 配置文件 # 进入主节点配置文件目录 cd /export/server/docker/kibana/config # 编辑单机版配置文件 vi kibana.ymlkibana.yml内容 # 主机地址,可以是…...

【AI视野·今日CV 计算机视觉论文速览 第283期】Thu, 4 Jan 2024
AI视野今日CS.CV 计算机视觉论文速览 Thu, 4 Jan 2024 Totally 85 papers 👉上期速览✈更多精彩请移步主页 Daily Computer Vision Papers LEAP-VO: Long-term Effective Any Point Tracking for Visual Odometry Authors Weirong Chen, Le Chen, Rui Wang, Marc P…...

sort实现自定义排序方法详解
使用 sort 实现自定义排序 目录 使用 sort 实现自定义排序1.sort 的基本用法2.sort 实现自定义排序3.结构体重载进行比较 1.sort 的基本用法 sort 库函数需要引入头文件algorithm,是一种排序算法,使用的排序逻辑可以看成是效率很高的快速排序或其的改进版本。平均时…...

【攻防世界】Reverse——secret-galaxy-300 writeup
由main函数查看相关代码,但是代码中并没有直接的关于flag的信息: int __cdecl main(int argc, const char **argv, const char **envp) {__main();fill_starbase(&starbase);print_starbase((int)&starbase);return 0; } void __cdecl fill_sta…...
Github Copilot 快速入门
GitHub Copilot 是一个由 GitHub 推出的人工智能编程助手,旨在帮助开发者通过自动代码建议和补全来提高编程效率和质量。作为一个人工智能配对程序员,它能够理解你的代码意图,并提供相关的代码片段,以帮助你更快地编写代码。这种技…...
c# wpf 的触发器,触发器Trigger种类,每个触发器的使用说明
触发器是一种强大的声明性机制,用于根据指定条件更改控件的外观或行为。触发器主要分为以下几种类型: Property Trigger 说明:当绑定到控件某个依赖属性的值发生改变时,Property Trigger会执行预定义的一组设置。例如,…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...