android 怎么自定义view
首先了解view的绘制流程:

所以onmeasure ---测量view
onlayout---确定view大小----》所以继承ViewGroup必须要重写onlayout,确定子view
而onDraw----是继承view时候需要操作的。
所以:自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件。
自定义View,一般是没有现成的view
序列化,大概有这个意思,不一定对。
自定义序列化: IOT
协议比如:物联网:蓝牙:传递的数据 串口 协议:
onmeasure的测量 是先从子布局开始还是先从父布局开始的?
----根据算法来控制的,比如view pageer就是父布局开始
MeasureSpec是什么
public static class MeasureSpec {private static final int MODE_SHIFT = 30;private static final int MODE_MASK = 0x3 << MODE_SHIFT;/** @hide */@IntDef({UNSPECIFIED, EXACTLY, AT_MOST})@Retention(RetentionPolicy.SOURCE)public @interface MeasureSpecMode {}
----是view里面的一个类---我们知道int 是32位
------上面代码里的30,就是高两位是00,后面30位---》所以这组成里MeasureSpec
-------高两位表示UNSPECIFIED,EXACTLY,AT_MOST
关于getChildMeasureSpec(int spec, int padding, int childDimension)算法
第一个参数,父亲给的,
第二个参数,父亲的
第三个参数,孩子需要的
-----》根据UNSPECIFIED,EXACTLY,AT_MOST来计算
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {int specMode = MeasureSpec.getMode(spec);int specSize = MeasureSpec.getSize(spec);int size = Math.max(0, specSize - padding);int resultSize = 0;int resultMode = 0;switch (specMode) {// Parent has imposed an exact size on uscase MeasureSpec.EXACTLY:if (childDimension >= 0) {resultSize = childDimension;resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) {// Child wants to be our size. So be it.resultSize = size;resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.WRAP_CONTENT) {// Child wants to determine its own size. It can't be// bigger than us.resultSize = size;resultMode = MeasureSpec.AT_MOST;}break;// Parent has imposed a maximum size on uscase MeasureSpec.AT_MOST:if (childDimension >= 0) {// Child wants a specific size... so be itresultSize = childDimension;resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) {// Child wants to be our size, but our size is not fixed.// Constrain child to not be bigger than us.resultSize = size;resultMode = MeasureSpec.AT_MOST;} else if (childDimension == LayoutParams.WRAP_CONTENT) {// Child wants to determine its own size. It can't be// bigger than us.resultSize = size;resultMode = MeasureSpec.AT_MOST;}break;// Parent asked to see how big we want to becase MeasureSpec.UNSPECIFIED:if (childDimension >= 0) {// Child wants a specific size... let them have itresultSize = childDimension;resultMode = MeasureSpec.EXACTLY;} else if (childDimension == LayoutParams.MATCH_PARENT) {// Child wants to be our size... find out how big it should// beresultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;resultMode = MeasureSpec.UNSPECIFIED;} else if (childDimension == LayoutParams.WRAP_CONTENT) {// Child wants to determine its own size.... find out how// big it should beresultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;resultMode = MeasureSpec.UNSPECIFIED;}break;}//noinspection ResourceTypereturn MeasureSpec.makeMeasureSpec(resultSize, resultMode);}
下面是一个流式布局的例子:
* desc : 官方FlexboxLayout 流式布局*/
class FlowLayout(context: Context) : ViewGroup(context) {private val mHorizontalSpacing = dp2px(16f) //每个item横向间距private val mVerticalSpacing = dp2px(8f) //每个item竖向间距private var allLines:MutableList<MutableList<View>> = ArrayList<MutableList<View>>() //记录所有的行,一行一行保存,用于layoutvar lineHeights:ArrayList<Int> = ArrayList()//记录每一行的行高,用于layoutconstructor(context: Context,attrs:AttributeSet):this(context){// 在这里处理从 XML 布局 --序列化格式--建值对}constructor(context: Context, attrs: AttributeSet, defStyle: Int) : this(context, attrs) {// 在这里处理从 XML 布局文件中传入的属性和样式}//初始化,因为是onMeasure递归的方式,所以要放在onMeasureprivate fun clearMeasureParams(){
// allLines =ArrayList<MutableList<View>>()
// lineHeights = ArrayList()allLines.clear()lineHeights.clear()}override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {clearMeasureParams()// 内存抖动
// super.onMeasure(widthMeasureSpec, heightMeasureSpec)//先度量孩子val childCount =childCount//ViewGroup解析父控件给我的宽高val selfWidth = MeasureSpec.getSize(widthMeasureSpec)val selfHeight =MeasureSpec.getSize(heightMeasureSpec)//measure过程中 子view要求的父viewgroup的宽高var parentNeededWidth =0;var parentNeededHeight =0;val linView = ArrayList<View>()var lineWidthUsed =0 //记录这一行的以及使用了多宽的sizevar lineHeight =0 //一行的杭高for (i in 0 until childCount){val childview = getChildAt(i)val childlayoutParams = childview.layoutParamsif (childview.visibility != GONE) {val childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,paddingLeft + paddingRight,childlayoutParams.width)val childHeightMeasureSpec1 = getChildMeasureSpec(heightMeasureSpec,paddingTop + paddingBottom,childlayoutParams.height)childview.measure(childWidthMeasureSpec, childHeightMeasureSpec1)//获取子view的度量高度val childMeasureWidth = childview.measuredWidthval childmeasuredHeight = childview.measuredHeightlinView.add(childview)//是否药换行if (childMeasureWidth + lineWidthUsed + mHorizontalSpacing > selfWidth) {//换行判断当前行所需要的宽和高,所以要记录下来allLines.add(linView)lineHeights.add(lineHeight) //行高。。这个if语句会缺少最后一行,parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacingparentNeededWidth =Math.max(parentNeededWidth, lineWidthUsed + mHorizontalSpacing)linView.clear()lineWidthUsed = 0lineHeight = 0}//每行自己的宽高lineWidthUsed = lineWidthUsed + childMeasureWidth + mHorizontalSpacinglineHeight = Math.max(lineHeight, childmeasuredHeight)//最后一行,if (i == childCount - 1) {allLines.add(linView)lineHeights.add(lineHeight)parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacingparentNeededWidth =Math.max(parentNeededWidth, lineWidthUsed + mHorizontalSpacing)}}}//度量自己//根据子view的度量结果,来重新度量自己的viewGroup//作为一个viewgroup,他自己也是个view,他的大小也需要根据他的父亲提供的宽高来度量var withmode: Int = MeasureSpec.getMode(widthMeasureSpec)var heightmode: Int = MeasureSpec.getMode(heightMeasureSpec)//确切的值 EXACTLYval realWidth =if(withmode ==MeasureSpec.EXACTLY) selfWidth else parentNeededWidthval realHeight =if(heightmode ==MeasureSpec.EXACTLY) selfHeight else parentNeededWidthsetMeasuredDimension(realWidth,realHeight)}override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {val lineCount =allLines.sizevar curl =paddingLeft //左边届var curT= paddingTop //上边界for(i in 0 until lineCount){val Lineviews = allLines.get(i)val lineHeight = lineHeights.get(i)for (j in 0 until Lineviews.size){//其中一行val view = Lineviews.get(j)//这一行的view//计算边界val left =curl //左边届val top= curT //上边界val right = left+measuredWidth//左边届val botton = top +measuredHeight //上边界view.layout(left,top,right,botton)curl =right+mHorizontalSpacing//下一个左边}curT =curT +lineHeight+mVerticalSpacing //下一个topcurl = paddingLeft //每一个新的行要重制左边届}// view.layout(left,top,right,bottom)}
}
相关文章:
android 怎么自定义view
首先了解view的绘制流程: 所以onmeasure ---测量view onlayout---确定view大小----》所以继承ViewGroup必须要重写onlayout,确定子view 而onDraw----是继承view时候需要操作的。 所以:自定义ViewGroup一般是利用现有的组件根据特定的布局…...
JavaScript的事件
JavaScript的事件 先写一个test测试函数以查看事件是否触发 function test(){var ddocument.getElementById("tid");console.log("测试成功"d) //控制台输出 }onclick 鼠标单击事件: <input type"button" id"tid" va…...
android 简单快速 自定义dialog(简单好用,不需要设置样式)
1.MyDialog代码: public class MyDialog{private Activity activity;private ViewGroup contentView;private View view;public MyDialog(Activity activity) {this.activityactivity;contentView activity.findViewById(android.R.id.content);viewLayoutInflate…...
JAVA代理模式梳理
什么是代理模式 代理模式:为其他对象提供一种代理,用以控制对这个对象的访问; 我们使用代理对象,可以在不修改目标对象的基础上,增强主业务逻辑;比如说我们的系统中有一个登录接口,我们要对这个…...
推荐几个线上兼职,每天两小时收入几十到一百
在当今数字化时代,居家兼职成为越来越多人的选择。借助互联网和技术的进步,我们能够轻松利用自己的时间和技能在网上赚取额外的收入。本文将为您介绍几个简单而有潜力的居家网上兼职小项目,帮助您实现财务自由。 1.千金宝库做任务赚钱 千金…...
excel封装和ddt D17
1)excel封装 openpyxl的操作 2)ddt 数据驱动测试 ## openpyxl的操作 1.安装:pip install openpyxl 2.导入 openpyxl: import openpyxl 3.workbook对象:工作簿,openpyxl.load_workbook() 4.sheet对象&a…...
PHP8编译安装
CentOS8编译安装PHP8 PHP,全称Hypertext Preprocessor(超文本预处理器),是一种通用开源脚本语言。它特别适合于web开发,并能嵌入HTML中。现在主要用于PHP网站中实现动态网站功能,常规我们使用nginx、apache…...
3D Gaussian Splatting for Real-Time Radiance Field Rendering(慢慢啃,还是挺复杂的)
三个关键要素 从相机配准的过程中得到的稀疏点云开始,使用3D Gaussian表示场景; 3D Gaussian: 是连续体积辐射场能够防止不必要的空空间优化。对 3D Gaussion进行交叉优化和密度控制: 优化各向异性血方差对场景精确表示。使用快速可视感知渲染算法来进行快速的训练…...
二叉树<II>:二叉树的四种遍历方式代码实现Python3
今天我们来介绍的是二叉树的「前序」、「中序」、「后序」、「层序」四种遍历方式如何用代码实现。 还不知道这四种遍历方式原理的可以看另一篇文章:二叉树<I>:概念及二叉树的前序遍历、中序遍历、后序遍历原理 1. 相关题目 这…...
vite ts vue 项目提示 . Projects must list all files or use an include pattern.
vite ts vue 项目提示 . Projects must list all files or use an include pattern. 在引用一个 ts 的时候,提示如下: 需要在 tsconfig.node.json 文件中添加: {"compilerOptions": {"composite": true,"skipLibC…...
鲸鱼优化算法改进风储机组一次调频出力分配系数,以频率偏差最小为目标优化函数,结合鲸鱼算法WOA捕食过程,改进风储出力分配系数simulink与matlab联合
simulink与matlab联合 风机模糊控制 改善后的系统频率 simulink.采用风储联合数学模型...
C语言经典面试题目(七)
1、C语言中如何进行内存对齐和字节对齐? 在C语言中,内存对齐和字节对齐是为了优化内存访问速度和提高系统性能而进行的一种策略。内存对齐是指数据在内存中的存放位置必须是某个值的倍数,通常是数据类型的大小。字节对齐是指数据在内存中的存…...
2024华为春招Django面试题大全,最全知识点揭秘,面试必备!
为了帮助广大求职者更好地准备即将到来的面试,本文精心编撰了一系列涵盖InnoDB存储引擎关键知识点的面试题。这些问题不仅覆盖了InnoDB的基础知识,如其ACID特性、索引设计、锁机制等,还涵盖了性能优化、备份恢复策略等高级话题,旨…...
搜维尔科技:使用SenseGlove Nova手套操纵其“CAVE”投影室中的虚拟对象
创造了一种基于 PC 的创新型多边沉浸式环境,让参与者完全被虚拟图像和声音包围。 需要解决的挑战: 传统的 VR 系统往往缺乏真实的触摸反馈,限制了用户的沉浸感。AVR Japan 旨在通过将触觉技术融入到他们的 CAVE 系统中来应对这一挑战&#x…...
独立服务器的优势
独立服务器的优势 高性能 独立服务器提供了卓越的性能,因为它们不与其他用户共享资源。这使得您的网站或应用程序能够快速响应访问请求,并处理大量数据。 安全性 由于没有其他租户在同一服务器上,独立服务器的安全性更高。您可以更好地控制…...
前端框架vue的样式操作,以及vue提供的属性功能应用实战
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
【自动化测试】如何在jenkins中搭建allure
相信大家在做自动化测试过程中,都会用到自动化测试环境,目前最常见的就是通过容器化方式部署自动化测试环境,但对于一些测试小白,不是很会搭建持续集成环境,特别是从0-1的过程,需要自行搭建很多依赖环境&am…...
2.域控如何强制转移操作主机角色?使用命令如何强制转移域控的操作角色?
1.实验环境介绍 实验1:模拟5种操作主机都在DC01上的域控宕机了 (1)实验先决条件 (2)测试的方向 实验2:域控夺权实验操作 方式1:AD用户和计算机工具转移操作主机角色 (1)RID角色转移: (2)PDC角色转移 (3)基础结构操作主机角色转移 方式2:powshell命令强制…...
C# event的使用
在C#中,事件(Event)是一种特殊的成员,它允许类或对象以类型安全的方式向外界发出通知,表明某个特定的行为或状态变化已经发生。 订阅该事件的其他类可以定义处理方法来响应这些通知。 事件主要基于委托机制实现&…...
外包干了9天,技术退步明显。。。。。
先说一下自己的情况,本科生,2018年我通过校招踏入了南京一家软件公司,开始了我的职业生涯。那时的我,满怀热血和憧憬,期待着在这个行业中闯出一片天地。然而,随着时间的推移,我发现自己逐渐陷入…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
