当前位置: 首页 > news >正文

重学Android:自定义View基础(一)

前言

作为一名安卓开发,也被称为大前端,做一个美观的界面,是我们必备的基础技能,可能在开发中我们最常用的是系统自带的View,因为他能满足绝大部分需求,难一点的我们也可以上Github上找个三方库使用,少数情况下会让我们进行自定义View,当然这不代表着我们可以不去掌握其原理,因为它是通往中高级程序员的必经之路,也是大厂面试的热门知识,只有熟练掌握其核心原理,才能让我们在后续的开发中游刃有余。

由于这是开篇文章,说的有点多,笔者是想借着写博客的机会,把那些最不经意的基础打牢一下,并且加上自己的拙见与大家分享,共同进步。

自定义View简介

自定义View是Android开发中的一种常见需求,它允许开发者创建复杂的用户界面组件,以满足特定的设计需求。自定义View的好处在于可以完全控制View的外观和行为。常见的是 extend Viewextend ViewGroup 以及系统自带的View

1. onMeasure


onMeasure方法用于测量View的尺寸。它的主要任务是决定View的宽度和高度。以下是一个简单的自定义View示例,它在onMeasure中实现了固定大小的测量逻辑。

示例代码

public class CustomView extends View {public CustomView(Context context) {super(context);}public CustomView(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 期望的宽高int desiredWidth = 200;int desiredHeight = 200;// 获取父View提供的宽高int width = MeasureSpec.getSize(widthMeasureSpec);int height = MeasureSpec.getSize(heightMeasureSpec);// 测量宽度width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY ?width : desiredWidth;// 测量高度height = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY ?height : desiredHeight;// 设置测量后的宽高setMeasuredDimension(width, height);}
}

2. onDraw


onDraw方法用于绘制View的内容。在此方法中,使用Canvas绘制图形或文字。

示例代码

@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);Paint paint = new Paint(); // 创建画笔paint.setColor(Color.BLUE); // 设置颜色为蓝色// 在中心绘制一个半径为100的圆canvas.drawCircle(getWidth() / 2, getHeight() / 2, 100, paint);
}

3. onTouch


onTouch方法用于处理触摸事件,使View能够响应用户的触摸操作。

示例代码

@Override
public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 处理按下事件// 可以在这里改变View的状态或外观break;case MotionEvent.ACTION_MOVE:// 处理移动事件// 例如,移动View或改变某些属性break;case MotionEvent.ACTION_UP:// 处理抬起事件// 可以在这里完成某个操作,比如动画结束break;}return true; // 返回true表示事件已被处理
}

4. 自定义属性


通过自定义属性,可以使自定义View在XML中更加灵活。如果你想写一个自定义View的三方库,自定义属性是必须掌握的。

定义

res/values/attrs.xml中添加自定义属性:

<declare-styleable name="CustomView"><attr name="customColor" format="color" /><attr name="customSize" format="dimension" />
</declare-styleable>

使用

在自定义View的构造函数中读取这些属性:

public CustomView(Context context, AttributeSet attrs) {super(context, attrs);TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.CustomView,0, 0);try {// 读取自定义颜色属性,默认为黑色int customColor = a.getColor(R.styleable.CustomView_customColor, Color.BLACK);// 读取自定义尺寸属性,默认为50dpfloat customSize = a.getDimension(R.styleable.CustomView_customSize, 50);// 使用customColor和customSize进行后续逻辑} finally {a.recycle(); // 释放TypedArray资源!!!}
}

5. 测量模式


在Android中,自定义View的测量过程由三种测量模式决定:EXACTLYAT_MOSTUNSPECIFIED

三种布局模式

在 Android 布局中,父 View 可以通过不同的模式给子 View 传递尺寸限制,常见的有以下三种模式:

1. EXACTLY(确切模式)
  • 定义:父 View 给子 View 传递了一个确切的尺寸,子 View 应该使用这个尺寸。
  • 适用场景:一般用于设置为 match_parent 或具体的尺寸值时。

例如,设置子 View 的宽度为父 View 的 100dp,子 View 必须遵循这一具体尺寸。


2. AT_MOST(最多模式)
  • 定义:父 View 给子 View 传递了一个最大尺寸,子 View 可以选择小于或等于这个尺寸。
  • 适用场景:一般用于设置为 wrap_content,子 View 根据内容大小自适应,但不能超过父 View 的最大限制。

例如,当子 View 选择包裹内容时,它会根据内容大小自适应,但不能超过父 View 给定的最大限制。


3. UNSPECIFIED(未指定模式)
  • 定义:父 View 没有给子 View 限制尺寸,子 View 可以根据自身需求决定尺寸。
  • 适用场景:一般用于需要自由尺寸的情况,例如 ListViewScrollView 中的子 View。

这种模式一般在自定义控件或特定场景下使用,较少应用于常规布局。

源码解析

在自定义View的onMeasure方法中,我们可以通过MeasureSpec类来解析这三种模式。MeasureSpec包含两个主要信息:Mode(模式)Size(大小)

MeasureSpec的源代码

public static final int UNSPECIFIED = 0;
public static final int EXACTLY = 1;
public static final int AT_MOST = 2;private static final int MODE_SHIFT = 30;
private static final int MODE_MASK  = 0x3 << MODE_SHIFT;//使用掩码(mask)来提取高2位。
public static int getMode(int measureSpec) {return (measureSpec & MODE_MASK);  // MODE_MASK = 0x3
}//通过掩码去除高2位,获取低30位的值。
public static int getSize(int measureSpec) {return (measureSpec & ~MODE_MASK);  // ~MODE_MASK = 0xFFFFFFFC
}

测量模式存储形式

MeasureSpec是一个32位的整数(int 值 4个字节,32bit),其中包含模式和大小信息。

  • 高位(位31到位30):用于存储模式。
  • 低位(位29到位0):用于存储大小。

二进制表示

EXACTLY0b01000000000000000000000000000000(只关心高两位)

public static final int EXACTLY     = 1 << MODE_SHIFT;

AT_MOST0b10000000000000000000000000000000

public static final int AT_MOST     = 2 << MODE_SHIFT;

UNSPECIFIED0b00000000000000000000000000000000

public static final int UNSPECIFIED = 0 << MODE_SHIFT;

各模式示例代码

  1. EXACTLY(确切模式)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 获取父View提供的确切宽高int width = MeasureSpec.getSize(widthMeasureSpec);int height = MeasureSpec.getSize(heightMeasureSpec);// 使用父View提供的尺寸setMeasuredDimension(width, height);
}

应用场景:当父布局设置为match_parent时,子View的宽高将完全匹配父布局。

  1. AT_MOST(最多模式)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int width;int height;// 处理宽度if (widthMode == MeasureSpec.AT_MOST) {// 计算子View的宽度,最大不超过widthSizewidth = Math.min(desiredWidth, widthSize);} else {width = desiredWidth; // 使用期望宽度}// 处理高度if (heightMode == MeasureSpec.AT_MOST) {// 计算子View的高度,最大不超过heightSizeheight = Math.min(desiredHeight, heightSize);} else {height = desiredHeight; // 使用期望高度}setMeasuredDimension(width, height);
}

应用场景:父布局使用wrap_content,子View可以根据内容自适应,但不会超过父布局的最大值。

  1. UNSPECIFIED(未指定模式)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 在此模式下,子View可以自由选择尺寸setMeasuredDimension(desiredWidth, desiredHeight);
}

应用场景:适用于需要灵活大小的场景,例如在ScrollView中,子View的尺寸可以根据内容进行扩展。

6. 安卓自定义View刷新调用顺序图

    ┌────────────────────┐│    调用invalidate() │└────────────────────┘↓┌────────────────────────────┐│  调用View.invalidate()     │└────────────────────────────┘↓┌──────────────────────────────┐│   调用ViewParent.invalidate() │ (若有父视图,向上请求刷新)└──────────────────────────────┘↓┌──────────────────────────────┐│   调用请求重绘机制:UI线程刷新 │└──────────────────────────────┘↓┌────────────────────────┐│ 调用requestLayout()    │  (如果布局变化,调用此方法会触发onMeasure)└────────────────────────┘↓┌────────────────────────────┐│  调用onMeasure()           │└────────────────────────────┘↓┌────────────────────────────┐│   调用setMeasuredDimension │  (设置最终宽高)└────────────────────────────┘↓┌────────────────────────┐│ 调用onLayout()         │ (进行视图的布局)└────────────────────────┘↓┌──────────────────────────────┐│ 调用onDraw()                 │  (进行绘制操作)└──────────────────────────────┘↓┌──────────────────────────────┐│    更新显示,重新渲染视图      │└──────────────────────────────┘

简单来说就是三步走,onMeasureonLayoutonDraw,其中onLayout一般情况下,普通视图不需要重写此方法,除非视图具有子视图并需要自己进行布局。比如你如果想自定义一个某东搜索框下面的历史搜索记录布局的时候,就必须重写onLayout了。

总结

方法作用何时重写
onMeasure()测量视图的大小当视图的尺寸依赖于父视图的MeasureSpec或动态计算时
onLayout()布局子视图的位置当视图是布局容器或需要动态布局子视图时
onDraw()绘制视图的内容当需要自定义视图内容的绘制时,几乎所有自定义视图都需要重写

7. 最后


基础只是理论概念,要想牢记,还得在实战中运用,当然上面都会了,就能和面试官吹牛逼了。再会!

另外给喜欢记笔记的同学安利一款好用的云笔记软件,对比大部分国内的这个算还不错的,免费好用:wolai

_

相关文章:

重学Android:自定义View基础(一)

前言 作为一名安卓开发&#xff0c;也被称为大前端&#xff0c;做一个美观的界面&#xff0c;是我们必备的基础技能&#xff0c;可能在开发中我们最常用的是系统自带的View&#xff0c;因为他能满足绝大部分需求&#xff0c;难一点的我们也可以上Github上找个三方库使用&#…...

前端好用的网站分享——CSS(持续更新中)

1.CSS Scan 点击进入CSS Scan CSS盒子阴影大全 2.渐变背景 点击进入color.oulu 3.CSS简化压缩 点击进入toptal 4.CSS可视化 点击进入CSS可视化 这个强推&#xff0c;话不多说&#xff0c;看图! 5.Marko 点击进入Marko 有很多按钮样式 6.getwaves 点击进入getwaves 生…...

华为HarmonyOS借助AR引擎帮助应用实现虚拟与现实交互的能力3-获取设备位姿

设备位姿描述了物体在真实世界中的位置和朝向。AR Engine提供了世界坐标下6自由度&#xff08;6DoF&#xff09;的位姿计算&#xff0c;包括物体的位置&#xff08;沿x、y、z轴方向位移&#xff09;和朝向&#xff08;绕x、y、z轴旋转&#xff09;。通过AR Engine&#xff0c;您…...

qt QColorDialog详解

1、概述 QColorDialog是Qt框架中的一个对话框类&#xff0c;专门用于让用户选择颜色。它提供了一个标准的颜色选择界面&#xff0c;其中包括基本的颜色选择器&#xff08;如调色板和颜色轮&#xff09;、自定义颜色输入区域以及预定义颜色列表。QColorDialog支持RGB、HSV和十六…...

【测试小白--如何写好测试用例--测试用例编写的方法+结合常见登录模块为实例--保姆级教学】

测试用例编写方法&登录模块实例 一、测试用例编写方法1. 等价类划分2. 边界值分析3. 状态转换测试4. 决策表测试5. 错误推测6. 用户场景测试7. 安全测试用例 二、登录模块测试用例实例1. 等价类划分2. 边界值分析3. 状态转换测试4. 决策表测试5. 错误推测6. 用户场景测试7.…...

真题--数组循环题目

1.逆序数表达数组2.用数组表示费波纳希数列3.用数组排序4.二维数组转置5.找到二维数组其中的最大数值6.输出字符数组7.字符数组输出菱形图案8.输入一行字符&#xff0c;统计有多少单词9.有三个字符串&#xff0c;找到最大字符串 1.逆序数表达数组 #include<stdio.h> int…...

【Linux系列】在Linux下安装微信

文章目录 前言一、通用Linux系统使用Flatpak安装&#xff08;推荐&#xff09;1. 安装flatpak2. 安装微信 二、国产Linux 前言 此前&#xff0c;微信的Linux版一直在内测阶段&#xff0c;只有在国产的Linux系统和Debian系系统上可以正常安装&#xff0c;如果有心细的好伙伴应该…...

还在使用ElementUI不如试一试DaisyUI,DaisyUI: Tailwind CSS 的高效组件库,

DaisyUI: Tailwind CSS 的高效组件库 daisyUI官网&#xff1a;https://daisyui.com/ 在现代网页开发中&#xff0c;快速构建美观且响应式的用户界面是每个开发者追求的目标。Tailwind CSS 是一个流行的实用程序优先的 CSS 框架&#xff0c;它允许开发者直接在 HTML 中使用预…...

高光谱激光雷达遥感团队成员白杰博士获全国激光雷达优博论文奖

\quad \quad 2024年11月1日—4日&#xff0c;第八届全国激光雷达大会在桂林理工大学大学召开。本届大会&#xff0c;国际数字地球学会中国国家委员会激光雷达专业委员会组织了本年度优秀博士学位论文评选&#xff0c;经初评、函评、投票和公示&#xff0c;最终评选出了全国激光…...

24年配置CUDA12.4,Pytorch2.5.1,CUDAnn9.5运行环境

没什么好介绍的&#xff0c;直接说了。 下载 首先打开命令行&#xff0c;输入代码查看显卡最高支持的cuda版本&#xff0c;下载的版本不要高于该版本 nvidia-smi PyTorch 插件这个是PyTorch下载地址&#xff0c;就按照我这么选CUDA版本就选最新的&#xff0c;看好绿框里的CU…...

基于springboot得高校评教教师工作量管理系统设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…...

Rust 力扣 - 1456. 定长子串中元音的最大数目

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们遍历长度为k的窗口&#xff0c;我们只需要记录窗口内的元音字母数量即可&#xff0c;遍历过程中刷新最大数目 题解代码 impl Solution {pub fn max_vowels(s: String, k: i32) -> i32 {let s s.as_byt…...

【Golang】validator库的使用

package mainimport ("fmt""github.com/go-playground/validator" )// MyStruct .. validate:"is-awesome"是一个结构体标签&#xff0c;它告诉验证器使用名为is-awesome的验证规则来验证String字段。 type MyStruct struct {String string vali…...

【AI日记】24.11.06 我对投资的一点浅见

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 投资学习 内容&#xff1a;看投资大佬访谈或演讲B站地址&#xff1a;巴菲特1998年佛州大学讲座目标&#xff1a;学习巴菲特的投资哲学和人生智慧时间&#xff1a;2小时评估&#xff1a;非常不错&#xff0c;值…...

2024江苏省网络建设与运维省赛Linux(一)系统安装

第五部分: Linux 系统配置( 20 分) (一)系统安装 【任务描述】 系统安装 (1)所有 Linux 服务器登录密码设置为 Netw@rkCZ!@#(注意区分大小写) (2)PC1 web 连接 Server2,给 Server2 安装 rocky-arm64 CLI 系统(语言为英文)。 (3)配置 server2 的 IPv4 地址为…...

详解Python面向对象程序设计

Python面向对象程序设计 1&#xff0c;初识类和对象2&#xff0c;类的定义和使用3&#xff0c;构造方法4&#xff0c;常用的类内置方法4.1&#xff0c;字符串方法&#xff1a;__str__ 4.2&#xff0c;是否小于&#xff1a;__lt__4.3&#xff0c;是否小于等于&#xff1a;__le__…...

JS保留两位小数

方法1 var num 3.14159; var result num.toFixed(2); 方法2 toFixed(2) 返回的是字符串&#xff0c;需要转数字。 var num 3.14159; var result parseFloat(num.toFixed(2));...

ClickHouse集成Mysql表引擎跨服务器读表说明

MySQL表引擎 Clickhouse 上的MySQL引擎可以对存在远程MySQL服务器上的数据执行SELECT查询。 调用格式&#xff1a; MySQL(host:port, database, table, user, password, replace_query, on_duplicate_clause); 调用参数 host:port — MySQL 服务器地址。 database — 数据…...

【AI构思渲染】别眨眼!这些图片立马变效果图!

我只是随手一拍白模模型 AI构思渲染立马就给我生成了非常amazing的效果图 下面我来一波展示给大家欣赏欣赏 1.白模模型照片变效果图&#xff1a; 渲染风格包&#xff1a;白模-城市鸟瞰 关键词&#xff1a;商业建筑&#xff0c;车辆&#xff0c;精美景观 词权重&#xff1a…...

多特征变量序列预测(10)基于麻雀优化算法的CEEMDAN-SSA-Transformer-BiLSTM预测模型

往期精彩内容&#xff1a; 时序预测&#xff1a;LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较 全是干货 | 数据集、学习资料、建模资源分享&#xff01; EMD变体分解效果最好算法——CEEMDAN&#xff08;五&#xff09;-CSDN博客 拒绝信息泄露&#xff01;VMD滚动分…...

算法学习(十)—— 字符串

关于字符串操作 这类题一般是和其它算法合起来&#xff0c;比如模拟&#xff0c;双指针&#xff0c;动态规划或者回溯等&#xff0c;所以字符串相关的题目类型一般是非常非常丰富的&#xff0c;这里我们选取几道经典的题目进行讲解 部分OJ题详解 14. 最长公共前缀 14. 最长…...

「Mac畅玩鸿蒙与硬件16」鸿蒙UI组件篇6 - List 和 Grid 组件展示数据列表

List 和 Grid 是鸿蒙开发中的核心组件&#xff0c;用于展示动态数据。List 适合展示垂直或水平排列的数据列表&#xff0c;而 Grid 则适用于展示商品或图片的网格布局。本篇将展示如何封装组件&#xff0c;并通过按钮实现布局切换&#xff0c;提升界面的灵活性和用户体验。 关键…...

masm汇编字符输入小写转大写演示

从键盘读取一个字符变成大写换行并输出 assume cs:codecode segmentstart:mov ah,1int 21hmov bl,alsub bl,20hmov dl,10mov ah,2int 21hmov dl,blmov ah,2int 21hmov ah,4chint 21hcode ends end start 效果演示&#xff1a;...

防火墙|WAF|漏洞|网络安全

防火墙|WAF|漏洞|网络安全 防火墙 根据内容分析数据包&#xff1a; 1、源IP和目的IP地址 2、有效负载中的内容。 3、数据包协议&#xff08;例如&#xff0c;连接是否使用 TCP/IP 协议&#xff09;。 4、应用协议&#xff08;HTTP、Telnet、FTP、DNS、SSH 等&#xff09;。 5…...

继承机制深度解析:从基础到进阶的完整指南

文章目录 1. 继承的概念及定义1.1 继承的概念&#xff1a;1.2继承的定义&#xff1a;1.2.1 定义格式1.2.2 继承基类成员访问方式的变化&#xff1a; 1.3继续类模板 2. 基类和派生类间的转换2.1 向上转换&#xff08;Upcasting&#xff09;2.2 向下转换&#xff08;Downcasting&…...

8. 数据结构——邻接表、邻接矩阵的基本操作

一、邻接表 1. 内容 2. 实现代码(直接可以复制使用) //邻接表的相关操作 #include<bits/stdc.h> #define MVnum 100 #define OK 1 #define ERROR -1 using namespace std;typedef int Status; typedef char VerTexType; //假设顶点的数据类型为char typedef int ArcT…...

OpenCV Python 版使用教程(二)摄像头调用

文章目录 一、上篇回顾二、使用步骤1. 调用摄像头的 API 介绍2. 代码示例3. 代码分析 三、下篇预告 一、上篇回顾 在上一篇中&#xff0c;简单介绍了如何在 Windows 和 Ubuntu 两个环境下部署和安装 OpenCV&#xff0c;从本篇开始将逐步介绍 OpenCV 中的常见操作。 本篇介绍 …...

基础算法——排序算法(冒泡排序,选择排序,堆排序,插入排序,希尔排序,归并排序,快速排序,计数排序,桶排序,基数排序,Java排序)

1.概述 比较排序算法 算法最好最坏平均空间稳定思想注意事项冒泡O(n)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)Y比较最好情况需要额外判断选择O( n 2 n^2 n2)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)N比较交换次数一般少于冒泡堆O( n l o g n nlogn nlogn)O( n l o g n nlogn nlogn)O( n l…...

几种常见的处理ARP欺骗的方法:静态ARP表和VLAN等

ARP&#xff08;Address Resolution Protocol&#xff09;欺骗是一种常见的网络攻击手段&#xff0c;攻击者通过伪造ARP响应&#xff0c;将网关的MAC地址指向攻击者的MAC地址&#xff0c;从而截获或篡改网络流量。为了应对ARP欺骗攻击&#xff0c;现代网络设备和管理员采取了一…...

突破1200°C高温性能极限!北京科技大学用机器学习合成24种耐火高熵合金,室温延展性极佳

在工程应用中&#xff0c;如燃气轮机、核反应堆和航空推进系统&#xff0c;对具备优异高温机械性能的金属合金需求十分旺盛。由于材料熔点的固有限制&#xff0c;传统镍基 (Ni) 高温合金的耐温能力已接近极限。为满足开发高温结构材料的需求&#xff0c;耐火高熵合金 (RHEAs) 于…...