布局过程的完全解析

news/2024/5/20 14:52:04/文章来源:https://blog.csdn.net/qq_35178391/article/details/132777392

前言

在这里插入图片描述
那么为什么要分为两个流程呢

因为测量流程是一个复杂的流程,有时候不一定一遍就能得出测量结果,可能需要 2 - 3 次甚至更多

在这里插入图片描述

自定义布局的几种类型,也是自定义布局的两个方法

在这里插入图片描述

实战,第一种类型:改写已有View 的步骤

在这里插入图片描述
需求:实现一个正方形的ImageView,以窄边作为变长,我们可以这样实现:

package com.example.viewtest.viewimport android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import kotlin.math.minclass SquareImageView(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs) {override fun layout(l: Int, t: Int, r: Int, b: Int) {val width = r - lval height = t - bval value = min(width, height)super.layout(l, t, r + value, b + value)}
}

这样可以实现我们的效果,但是为什么不能这样写呢?

因为这是父View在他的OnLayout方法中会调用字view的layout,让子view将自己的尺寸保存下来,而我们在这个过程中修改了自己的尺寸,父view是不知道的,后续的过程中父view会一直认为我们的尺寸是他传给我们的那个,会发生意想不到的效果

比方说我们在xml中声明的这个view 的宽是300,高是200,在这个view的右边紧挨着放了另一个view,运行的效果会发现这两个view中间有100的距离,就是因为父view认为你是300,而你实际把自己改成了200

接下来展示正确的写法

package com.example.viewtest.viewimport android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import kotlin.math.minclass SquareImageView(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs) {override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {// 保留这个方法,让父布局去测量我的结果,我的宽高super.onMeasure(widthMeasureSpec, heightMeasureSpec)// 通过这两个拿到测量之后的结果val value = min(measuredWidth, measuredHeight)// 修改后的值直接保存,这样才有意义,才会起到作用// 不是通过返回值将结果返回给父view,因为之后不一定是父view在使用setMeasuredDimension(value, value)// measuredWidth、width 的区别// measuredWidth 是测量过程中的值,width 是最终的结果值,父view可能会对measuredWidth进行修改,他俩可能值不一样// width 只有测量结束才能拿到结果,即使是刷新,在刷新完成之前虽然有值,也是上一次的测量结果// 在测量过程中应该使用 measuredWidth,高同理}}

这里额外说一下 measuredWidthwidth 的区别(高同理

    // measuredWidth、width 的区别// measuredWidth 是测量过程中的值,width 是最终的结果值,父view可能会对measuredWidth进行修改,他俩可能值不一样// width 只有测量结束才能拿到结果,即使是刷新,在刷新完成之前虽然有值,也是上一次的测量结果// 在测量过程中应该使用 measuredWidth,高同理

实战,第二种类型:完全自定义View的尺寸

步骤
在这里插入图片描述

package com.example.viewtest.viewimport android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import androidx.appcompat.widget.AppCompatImageView
import com.example.viewtest.R
import com.example.viewtest.ext.dp
import kotlin.math.minprivate const val PADDING = 100f
private const val RADIUS = 100f
class CircleView(context: Context, attrs: AttributeSet) : View(context, attrs) {private val paint = Paint(Paint.ANTI_ALIAS_FLAG)override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)val size = (PADDING + RADIUS) * 2/*** resolveSize 的作用* 一值两用,通过 MeasureSpec.getMode 判断返回的约束条件;通过 MeasureSpec.getSize 获取真实的值* 如果强制类型,那么使用父类给的值,如果是范围类型,则谁小使用谁,其他则随意使用*/val width = resolveSize(size.toInt(), widthMeasureSpec)val height = resolveSize(size.toInt(), heightMeasureSpec)setMeasuredDimension(width, height)}override fun onDraw(canvas: Canvas) {super.onDraw(canvas)canvas.drawCircle(PADDING + RADIUS, PADDING + RADIUS, RADIUS , paint)}}

实战,第三种类型:完全自定义View的尺寸

在这里插入图片描述

import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import android.view.ViewGroup
import androidx.core.view.children
import kotlin.math.maxclass TagLayout(context: Context?, attrs: AttributeSet?) : ViewGroup(context, attrs) {private val childrenBounds = mutableListOf<Rect>()override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {var widthUsed = 0var heightUsed = 0var lineWidthUsed = 0var lineMaxHeight = 0val specWidthSize = MeasureSpec.getSize(widthMeasureSpec)val specWidthMode = MeasureSpec.getMode(widthMeasureSpec)for ((index, child) in children.withIndex()) {// 测量子类的限制类型以及他的宽,确定他最终的真实宽度measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, heightUsed)// 判断是否需要换行,换行需要重制上一行的内容if (specWidthMode != MeasureSpec.UNSPECIFIED &&lineWidthUsed + child.measuredWidth > specWidthSize) {lineWidthUsed = 0heightUsed += lineMaxHeightlineMaxHeight = 0measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, heightUsed)}if (index >= childrenBounds.size) {childrenBounds.add(Rect())}val childBounds = childrenBounds[index]childBounds.set(lineWidthUsed, heightUsed, lineWidthUsed + child.measuredWidth, heightUsed + child.measuredHeight)lineWidthUsed += child.measuredWidth// 已经使用的最大宽度为当我自己的宽度widthUsed = max(widthUsed, lineWidthUsed)// 当前行的最大高度lineMaxHeight = max(lineMaxHeight, child.measuredHeight)}val selfWidth = widthUsedval selfHeight = heightUsed + lineMaxHeight// 确定我自己的宽高setMeasuredDimension(selfWidth, selfHeight)}override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {for ((index, child) in children.withIndex()) {val childBounds = childrenBounds[index]child.layout(childBounds.left, childBounds.top, childBounds.right, childBounds.bottom)}}// 调用 measureChildWithMargins 时会强转报错override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {return MarginLayoutParams(context, attrs)}
}

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

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

相关文章

Unity中Shader抓取屏幕并实现扭曲效果

文章目录 前言一、屏幕抓取&#xff0c;在上一篇文章已经写了二、实现抓取后的屏幕扭曲实现思路&#xff1a;1、屏幕扭曲要借助传入 UV 贴图进行扭曲2、传入贴图后在顶点着色器的输入参数处&#xff0c;传入一个 float2 uv : TEXCOORD&#xff0c;用于之后对扭曲贴图进行采样3、…

SQL Server2022安装教程

SQL Server 是一个关系数据库管理系统。它最初是由Microsoft、Sybase 和Ashton-Tate三家公司共同开发的&#xff0c;于1988 年推出了第一个OS/2版本。在Windows NT 推出后&#xff0c;Microsoft与Sybase 在SQL Server 的开发上就分道扬镳了&#xff0c;Microsoft 将SQL Server移…

mac电脑安装paste教程以及重新安装软件后不能使用解决方法

问题背景 mac电脑安装paste教程以及重新安装软件后不能使用解决方法。 mac电脑安装paste失败&#xff0c;安装好后还是无法使用&#xff0c;paste显示还是历史粘贴信息&#xff0c;导致无法使用。新 copy的内容也无法进入历史粘贴版里面。 笔者电脑配置信息&#xff1a;MacB…

GLSL ES着色器 精度限定字

目录 前言 WebGL支持的三种精度 数据类型的默认精度 float类型没有默认精度 预处理指令 在GLSL ES中常用的三种预处理指令。 预定义的内置宏 前言 GLSL ES新引入了精度限定字&#xff0c;目的是帮助着色器程序提高运行效率&#xff0c;削减内存开支。顾名思义&#xf…

Linux C : select简介和epoll 实现

目录 一、基础知识 二、select 模型服务流程 二、select 模式的缺点。 三、poll 概要 四、epoll 服务端实现流程 1.epoll_create&#xff1a; 2.epoll_ctl 3.epoll_wait 五、epoll示例代码实现 1.epoll实现服务端 2.客户端采用tcp进行访问 一、基础知识 首先要知道&…

wpf C# 用USB虚拟串口最高速下载大文件 每包400万字节 平均0.7s/M,支持批量多设备同时下载。自动识别串口。源码示例可自由定制。

C# 用USB虚拟串口下载大文件 每包400万字节 平均0.7s/M。支持批量多设备同时下载。自动识别串口。可自由定制。 int 32位有符号整数 -2147483648~2147483647 但500万字节时 write时报端口IO异常。可能是驱动限制的。 之前用这个助手发文件&#xff0c;连续发送&#xff0…

微信小程序AI类目-深度合成-AI问答/AI绘画 互联网信息服务算法备案审核通过教程

近期小程序审核规则变化后&#xff0c;很多使用人类小徐提供的chatGPT系统的会员上传小程序无法通过审核&#xff0c;一直提示需要增加深度合成-AI问答、深度合成-AI绘画类目&#xff0c;该类目需要提供互联网信息服务算法备案并上传资质&#xff0c;一般对企业来说这种务很难实…

kafka学习-消费者

目录 1、消费者、消费组 2、心跳机制 3、消费者常见参数配置 4、订阅 5、反序列化 基本概念 自定义反序列化器 6、位移提交 6.1、自动提交 6.2、手动提交 同步提交 异步提交 7、再均衡 7.1、定义与基本概念 7.2、缺陷 7.3、如何避免再均衡 7.4、如何进行组内分…

Leangoo领歌 -敏捷任务管理软件,任务管理更轻松更透明

​任务管理&#xff0c;简单易懂&#xff0c;就是对任务进行管理。那怎么可以更好进行任务管理呢&#xff1f;怎么样样可以让任务进度可视化&#xff0c;一目了然呢&#xff1f;有效的管理可以让我们事半功倍。 接下来我们看一下如何借助任务管理软件高效的做任务管理。 首先…

国际版腾讯云/阿里云:云解析DNS是什么

云解析DNS是什么 ​ 问答 云解析DNS是一种安全、快速、安稳、牢靠的威望DNS解析处理服务。 云解析DNS为企业和开发者将易于处理辨认的域名转换为计算机用于互连通讯的数字IP地址&#xff0c;然后将用户的拜访路由到相应的网站或应用服务器。 云解析 DNS&#xff08;Domain Nam…

vue学习之事件绑定

事件绑定 创建 demo5.html,内容如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</…

DQN模型

1. DQN模型 References [1] 强化学习第五节&#xff08;DQN&#xff09;【个人知识分享】_哔哩哔哩_bilibili

LeetCode算法心得——判断能否在给定时间到达单元格(动态模拟)

大家好&#xff0c;我是晴天学长&#xff0c;这是一个动态模拟题&#xff0c;跟大佬相比&#xff0c;我的有点繁琐了&#xff0c;但是也算是锻炼到自己的一些细节问题&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。 1) .判断能否在给定时间到达单元…

Paper: 利用RNN来提取恶意软件家族的API调用模式

论文 摘要 恶意软件家族分类是预测恶意软件特征的好方法&#xff0c;因为属于同一家族的恶意软件往往有相似的行为特征恶意软件检测或分类方法分静态分析和动态分析两种&#xff1a; 静态分析基于恶意软件中包含的特定签名进行分析&#xff0c;优点是分析的范围覆盖了整个代码…

【C++】list的模拟实现【完整理解版】

目录 一、list的概念引入 1、vector与list的对比 2、关于struct和class的使用 3、list的迭代器失效问题 二、list的模拟实现 1、list三个基本函数类 2、list的结点类的实现 3、list的迭代器类的实现 3.1 基本框架 3.2构造函数 3.3 operator* 3.4 operator-> 3…

vue学习之条件渲染

条件渲染 用于控制组件显示创建 demo6.html,内容如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&…

【数据结构】——排序的相关习题

目录 一、选择填空判断题题型一&#xff08;插入排序——直接插入排序&#xff09;题型二&#xff08;插入排序——折半插入排序&#xff09;题型三&#xff08;插入排序——希尔排序&#xff09;题型四&#xff08;交换排序——冒泡排序&#xff09;题型五&#xff08;交换排序…

Linux内存管理--smaps内存

一、内存的两个概念 了解smaps内存之前要先搞清楚Linux内存管理中的虚拟内存&#xff08;Virtual Memory&#xff09;和驻留内存&#xff08;Resident Memory&#xff09;两个概念。 1、虚拟内存 首先需要强调的是虚拟内存不同于物理内存&#xff0c;虽然两者都包含内存字眼…

[EROOR] SpringMVC之500 回调函数报错

首先&#xff0c;检查一下idea里面的报错的原因&#xff0c;我的是jdk的版本的问题。所以更换一下就可以了。

SpringMVC常用注解、参数传递及页面跳转

一.SpringMVC常用注解 1.1.RequestMapping RequestMapping注解是一个用来处理请求地址映射的注解&#xff0c;可用于映射一个请求或一个方法&#xff0c;可以用在类或方法上。 标注在方法上运行代码 用于方法上&#xff0c;表示在类的父路径下追加方法上注解中的地址将会访…