自定义ViewGroup实现流式布局
目录
1、View的绘制流程
2、自定义ViewGroup构造函数的作用
3、onMeasure 方法
3.1、View的度量方式
3.2、onMeasure方法参数的介绍
3.3、自定义ViewGroup onMeasure 方法的实现
4、onLayout方法
5、onDraw方法
6、自定义View的生命周期
7、自定义流式布局的实现
扩展:
1、View的绘制流程
2、自定义ViewGroup构造函数的作用
/**
* 通过 new FlowLayout() 代码创建
* @param context
*/
public FlowLayout(Context context) {super(context);
}/**
* 通过xml解析创建
* @param context
* @param attrs
*/
public FlowLayout(Context context, AttributeSet attrs) {super(context, attrs);
}/**
* 自定义View 默认的属性以及自定义的属性
* @param context
* @param attrs
* @param defStyleAttr
*/
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);
} 3、onMeasure 方法
3.1、View的度量方式
3.2、onMeasure方法参数的介绍
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} 3.3、自定义ViewGroup onMeasure 方法的实现
- 度量子View(深度递归,因为ViewGroup不是叶子节点,一定要度量子View的宽高)
- 根据子View度量后的宽高计算ViewGroup的宽高
- 在度量子View的宽高时要考虑ViewGroup的padding和子View的margin值。
- 在计算ViewGroup的宽高时,要使用子View度量后的宽高,(ViewGroup分配给子View的宽高可能会大,需要子View执行onMeasure方法后确定自己的宽高)
- 在计算ViewGroup的宽高时要加入ViewGroup的padding值。
4、onLayout方法
- 在自定义ViewGroup的 onLayout中,需考虑ViewGroup的padding和子View的margin值
- 在自定义View中不用实现onLayout。
5、onDraw方法
6、自定义View的生命周期
7、自定义流式布局的实现
package com.liluj.androidui.custom;import static com.scwang.smartrefresh.layout.util.SmartUtil.dp2px;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.liluj.androidui.utils.UnitConvertUtils;
import java.util.ArrayList;
import java.util.List;/**
* 自定义流式布局
*/
public class FlowLayout extends ViewGroup {//水平间隔private int horizontalSpace = dp2px(20);//垂直间隔private int veticalSpace = dp2px(20);private List<List<View>> lineViewList; //记录每行的Viewprivate List<Integer> heightList; //记录每列的高度。/*** 通过 new FlowLayout() 代码创建* @param context*/public FlowLayout(Context context) {super(context);}/*** 通过xml解析创建* @param context* @param attrs*/public FlowLayout(Context context, AttributeSet attrs) {super(context, attrs);}/*** 自定义View 默认的属性以及自定义的属性* @param context* @param attrs* @param defStyleAttr*/public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);}private void initMeasure() {/*** 此两个参数是为了给Layout布局用的,界面不只绘制一次,会重新绘制,所以在每次执行onMeasure时要重新初始化,而不是在创建FlowLayout时初始化*/lineViewList = new ArrayList();heightList = new ArrayList<>();}/*** 依据子View的宽高 确定自己的宽高* 注意:* 1、margin值在父控件中处理* 1.1 当前ViewGroup的margin值在父控件已处理* 1.2 在度量和布局子View时要考虑margin值,否则子View的margin属性无用(此例子没处理子View的margin值)* 2、padding值包含在ViewGroup以及View的宽高* 2.1 在ViewGroup和View的 onMeasure、onLayout、onDraw时要考虑自身的padding值* @param widthMeasureSpec horizontal space requirements as imposed by the parent.* The requirements are encoded with* {@link android.view.View.MeasureSpec}.* @param heightMeasureSpec vertical space requirements as imposed by the parent.* The requirements are encoded with* {@link android.view.View.MeasureSpec}.**/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);initMeasure();int count = getChildCount();List<View> lineView = new ArrayList<>();int lineUsedWidth = 0; //当前行已使用的宽度int lineHeight = 0; //当前行的高度int mWidth = 0; //view的宽度int mHeight = 0; //view的高度/*** 父控件根据自己的宽高以及当前View的LayoutParam属性(宽、高、margin)分配给当前View的宽高,固定值就是固定值,* match_parent和wrap_content为父控件的宽度,*/int maxWidth = MeasureSpec.getSize(widthMeasureSpec);//子View可使用的最大宽度,需减去ViewGroup的paddingLeft和paddingRightint childrenCanUseWidth = maxWidth - getPaddingLeft()-getPaddingRight();int maxHeight = MeasureSpec.getSize(heightMeasureSpec);/*** 度量子View并计算ViewGroup属性为wrap_content时实际的宽高*/for(int i = 0;i<count;i++){View view = getChildAt(i);/*** 根据当前View的MeasureSpec属性、padding值和子View的LayoutParams值(android:layout_width和android:layout_height的属性值)来给子View分配空间*/int measureSpecWidth = getChildMeasureSpec(widthMeasureSpec,getPaddingLeft()+getPaddingRight(),view.getLayoutParams().width);int measureSpecHeight = getChildMeasureSpec(heightMeasureSpec,getPaddingTop()+getPaddingBottom(),view.getLayoutParams().height);/*** 触发子View度量自己的空间,子View度量自己的大小后校正子View的大小*/view.measure(measureSpecWidth,measureSpecHeight);int measuredWidth = view.getMeasuredWidth();int measuredHeight = view.getMeasuredHeight();//换行if(lineUsedWidth + measuredWidth > childrenCanUseWidth){lineViewList.add(lineView);heightList.add(lineHeight);mWidth = Math.max(mWidth,lineUsedWidth);mHeight = mHeight + lineHeight + veticalSpace;lineUsedWidth = 0;lineHeight = 0;lineView = new ArrayList<>();}lineView.add(view);lineUsedWidth = lineUsedWidth + measuredWidth + horizontalSpace;lineHeight = Math.max(lineHeight, measuredHeight);/*** 添加上最后一行的宽高*/if(i == count -1){lineViewList.add(lineView);heightList.add(lineHeight);mWidth = Math.max(mWidth,lineUsedWidth);mHeight = mHeight + lineHeight;}}//ViewGroup的宽高加上padding值mWidth = mWidth+getPaddingLeft()+getPaddingRight();mHeight = mHeight+getPaddingTop()+getPaddingBottom();/*** 获取当前View 宽高的mode*/int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);/*** 当View的宽高为固定值时,使用固定值,此处固定值只会比按照wrap_content计算出来的值大,不会小,与父控件分配给当前View的宽高值有关。* 可参见ViewGroup的getChildMeasureSpec方法*/int realWidth = (widthMode == MeasureSpec.EXACTLY) ? maxWidth:mWidth;int realHeight = (heightMode == MeasureSpec.EXACTLY) ? maxHeight:mHeight;setMeasuredDimension(realWidth,realHeight);}/*** 布局子View,布局子View时使用相对坐标(相对父View进行布局)而不是绝对坐标(Window坐标系)* @param changed This is a new size or position for this view* @param l Left position, relative to parent* @param t Top position, relative to parent* @param r Right position, relative to parent* @param b Bottom position, relative to parent*/@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {int curL = getPaddingLeft();int curT = getPaddingTop();for(int i = 0;i< lineViewList.size();i++){List<View> lineView = lineViewList.get(i);for(int j = 0;j<lineView.size();j++){View view = lineView.get(j);int left = curL;int top = curT;int right = curL + view.getMeasuredWidth();int bottom = curT + view.getMeasuredHeight();view.layout(left,top,right,bottom);curL = right + horizontalSpace;}curL = getPaddingLeft();curT = curT + heightList.get(i)+veticalSpace;}}
}
扩展:
- 将xml解析为UI
相关文章:
自定义ViewGroup实现流式布局
目录 1、View的绘制流程 2、自定义ViewGroup构造函数的作用 3、onMeasure 方法 3.1、View的度量方式 3.2、onMeasure方法参数的介绍 3.3、自定义ViewGroup onMeasure 方法的实现 4、onLayout方法 5、onDraw方法 6、自定义View的生命周期 7、自定义流式布局的实现 扩展ÿ…...
Git版本控制
目录 版本控制 概念 为什么需要版本控制? 常见的版本控制工具 Git 1、安装 2、了解基本的Linux命令 3、配置git 用户名和邮箱 4、git 工作模式 5、git 项目管理 6、git 分支 托管平台 远程仓库 Gitee 关联多个远程库 Git服务器 Git GUI 版本控制 概…...
若依之权限处理
若依之权限处理 若依前后端不分离版本使用的是shiro进行权限控制,本文主要是对shiro在若依中的使用进行分析。 RBAC权限模型 RBAC是指基于角色的访问控制。其基本思想是,对系统的各种权限不是直接授予具体的用户,而是在用户集合与权限集合…...
华为OD机试真题 Java 实现【矩阵最大值】【2023 B卷 100分】,附详细解题思路
一、题目描述 给定一个仅包含0和1的N*N的二维矩阵,请计算二维矩阵的最大值。 计算规则如下: 1、每行元素按下标顺序组成一个二进制数(下标越大越排在低位),二进制数的值就是该行的值。矩阵各行值之和为矩阵的值。 2、允许通过向左或向右整体循环移动每行元素来改变各元…...
ModuleNotFoundError: No module named ‘transformers_modules.chatglm-6b_v1‘的解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
MMPretrain代码课
安装注意事项 训练时需要基于算法库源码进行开发,所以需要git clone mmpretrain仓库。如果只调用,则pip install 即可。 from mmpretrain import get_model, list_models,inference_model分别用于模型的获取、例举、推理 此时还没加载预训练权重 tor…...
Selenium自动化程序被检测为爬虫,怎么屏蔽和绕过
Selenium 操作被屏蔽 使用selenium自动化网页时,有一定的概率会被目标网站识别,一旦被检测到,目标网站会拦截该客户端做出的网页操作。 比如淘宝和大众点评的登录页,当手工打开浏览器,输入用户名和密码时,…...
Nvidia Jetson Orin:开发技巧
Jetson PXXX定义 P2180 -> Jetson TX1 P3310 -> Jetson TX2 P3489 -> Jetson TX2i P3448 -> Jetson Nano devkit P3448-0020 -> Jetson Nano production module P2888 -> Jetson Xavier P2888-0060 -> Jetson Xavier-8GB P3701 -> Jetson AGX Orin D…...
为什么需要 git 和 相关的小知识
为什么需要git和相关的小知识 先看一个实际需求,引出Git 问题: 公司五一活动计划 ● 先说一个最简单的情况,比如你做了公司五一活动计划书(如图) 解决方案: 版本管理工具(Git) 一句话: Git 是目前最流行的分布式版本控制软件 Git 是怎么来的? Git…...
(详解)vue中实现主题切换的三种方式
目录 一、背景 二、实现思路 方法1:定义全局的CSS变量 方法2:切换已定义好的css文件 方法3:切换顶级CSS类名 (需使用css处理器,如sass、less等) 一、背景 在我们开发中我们会遇到像是需要切换程序风格、主题切换啦这种应用场景。 参考大佬…...
英国皇家植物园采用机器学习预测植物抗疟性,将准确率从 0.46 提升至 0.67
内容一览:疟疾是严重危害人类生命健康的重大传染病,研究人员一直在致力于寻找新的植物源性抗疟疾化合物,以研发相关药物。近期英国皇家植物园利用机器学习 算法 有效预测了植物抗疟性,该研究成果目前已发表在《Frontiers in Plant…...
基于Locust实现MQTT协议服务的压测脚本
一、背景简介 业务背景大概介绍一下,就是按照国标规定,车辆需要上传一些指定的数据到ZF的指定平台,同时车辆也会把数据传到企业云端服务上,于是乎就产生了一些性能需求。 目前我们只是先简单的进行了一个性能场景的测试…...
AURIX TC3XX Cached PFLASH与Non-Cached PFLASH的区别
Cached ? Non-Cached? 在阅读TC3XX的用户手册时,在内存映射表中,有两个segment都是Program Flash,而且大小都一样是3M,一个是segment 8 另一个是segment10 这难免让人产生疑惑,二者区别在哪? …...
uniapp开发小程序-显示左滑删除效果
一、效果图: 二、代码实现: <template><view class"container"><view class"myorderList"><uni-swipe-action><uni-swipe-action-item class"swipe-action-item" :right-options"option…...
FPGA 的数字信号处理:Verilog 实现简单的 FIR 滤波器
该项目介绍了如何使用 Verilog 实现具有预生成系数的简单 FIR 滤波器。 绪论 不起眼的 FIR 滤波器是 FPGA 数字信号处理中最基本的模块之一,因此了解如何将具有给定抽头数及其相应系数值的基本模块组合在一起非常重要。因此,在这个关于 FPGA 上 DSP 基础…...
使用粒子群优化算法(PSO)辨识锂电池二阶RC模型参数(附MATLAB代码)
目录 一、原理部分 二、代码详解部分 三、结果及分析 一、原理部分 PSO算法由美国学者于 1995 年提出,因其算法简单、效果良好,而在很多领域得到了广泛应用。该算法的起源是模拟鸟群的觅食过程,形成一种群体智能搜索算法。 其核心是&#…...
如何利用地面控制点实现倾斜摄影三维模型数据的几何坐标变换和纠正?
如何利用地面控制点实现倾斜摄影三维模型数据的几何坐标变换和纠正? 倾斜摄影是一种在空中拍摄地表物体的技术,可以获得高分辨率、高精度的三维模型数据,广泛应用于城市规划、建筑设计、土地管理等领域。然而,由于航拍时无法避免姿…...
设计规则之里氏替换原则
tip: 作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。 相关规则: 推荐:体系化学习Java(Java面试专题) 1.6大设…...
【叠高高】叠蛋糕游戏的微信小程序开发流程详解
记得小时候玩过的搭积木游戏吗,和叠高高游戏原理差不多的,与之类似的还有盖高楼游戏,就是看谁盖的(叠的)最高,这里讲一下比较基础的叠高高游戏小程序实现过程,对编程感兴趣的同学可以参考学习一…...
收集关键词的方法有哪些?(如何查找精准的行业流量关键词)
关键词的收集通常可以通过以下几种方法: 关键词收集方法 1.根据市场价值、搜索词竞争性和企业实际产品特征进行筛选:确定您的关键词列表之前,建议先进行市场分析,了解您的竞争对手、行业状况和目标受众等信息,以更好地了解所需的特…...
Z-Image-Turbo-rinaiqiao-huiyewunv 可视化流程设计:使用Visio绘制模型服务架构与数据流图
Z-Image-Turbo-rinaiqiao-huiyewunv 可视化流程设计:使用Visio绘制模型服务架构与数据流图 作为一名技术架构师,我经常需要向团队、客户或管理层解释一个复杂的系统是如何工作的。光靠文字描述,往往事倍功半。一张清晰的架构图或数据流图&am…...
Canvas Quest人像修复与增强实战:老照片修复与画质提升
Canvas Quest人像修复与增强实战:老照片修复与画质提升 1. 老照片修复的痛点与解决方案 翻开家里的老相册,总能看到一些泛黄、破损或模糊的照片。这些承载着珍贵记忆的画面,往往因为年代久远而变得难以辨认。传统的手工修复不仅耗时费力&am…...
2023年VSCode插件开发全指南:从零发布你的第一个扩展(TypeScript版)
2023年TypeScript生态下的VSCode插件开发实战 在当今开发者工具生态中,Visual Studio Code以其轻量化和高度可扩展性占据了绝对领先地位。根据2023年Stack Overflow开发者调查报告,VSCode以74.48%的使用率成为最受欢迎的代码编辑器。而插件系统正是其生态…...
新手别慌!手把手教你用嘉立创EDA专业版搞定蓝桥杯平衡车PCB布局布线
从零到精通:嘉立创EDA专业版实战蓝桥杯平衡车PCB设计全攻略 第一次接触蓝桥杯电子设计竞赛的平衡车项目时,面对密密麻麻的元器件和错综复杂的布线要求,很多同学都会感到无从下手。本文将带你一步步攻克这个看似复杂的PCB设计任务,…...
别再被Kettle的流程线骗了!详解‘阻塞数据直到步骤都完成’控件的正确用法与避坑指南
Kettle并行执行模型深度解析:如何正确使用"阻塞数据直到步骤都完成"控件 在ETL工具Kettle的使用过程中,许多开发者都会遇到一个令人困惑的现象:明明在转换中画了流程线,步骤却没有按照预期的顺序执行。这种认知偏差往往…...
如何用Penpot构建完整的用户体验地图和用户旅程:7步打造完美设计流程
如何用Penpot构建完整的用户体验地图和用户旅程:7步打造完美设计流程 【免费下载链接】penpot Penpot - The Open-Source design & prototyping platform 项目地址: https://gitcode.com/GitHub_Trending/pe/penpot Penpot作为开源的设计与原型平台&…...
如何实现ElasticHQ与ElasticSearch 8.x的完美兼容:未来就绪的监控解决方案
如何实现ElasticHQ与ElasticSearch 8.x的完美兼容:未来就绪的监控解决方案 【免费下载链接】elasticsearch-HQ Monitoring and Management Web Application for ElasticSearch instances and clusters. 项目地址: https://gitcode.com/gh_mirrors/el/elasticsearc…...
OpenClaw隐私保护实践:GLM-4.7-Flash本地处理敏感数据
OpenClaw隐私保护实践:GLM-4.7-Flash本地处理敏感数据 1. 为什么选择本地化方案处理敏感数据 去年我在处理一批客户合同时遇到了一个棘手问题——合同中包含大量身份证号、银行账号等敏感信息,而团队当时使用的云端AI解析服务需要上传完整文件。虽然服…...
一文搞懂Agent三大核心技术:Function Calling、MCP、A2A,小白也能轻松收藏学习!
本文详细解析了AI Agent的三大核心技术:Function Calling、MCP和A2A。Function Calling使AI能够主动获取外部信息,MCP为工具接入提供了标准化接口,而A2A则实现了多智能体之间的协作。通过这三个技术的演进,AI Agent的能力从点对点…...
别啃书了!用这款70块的Steam游戏《Turing Complete》,手把手带你从逻辑门拼出CPU
从逻辑门到CPU:用《Turing Complete》重构计算机组成原理学习体验 当我在大学第一次翻开《计算机组成原理》教材时,那些密密麻麻的逻辑门符号和抽象的数据通路图让我头皮发麻。直到在Steam上发现标价70元的《Turing Complete》——这款看似简单的电路模拟…...
