Android学习总结之自定义view设计模式理解

面试题 1:请举例说明自定义 View 中模板方法模式的应用

考点分析

此问题主要考查对模板方法模式的理解,以及该模式在 Android 自定义 View 生命周期方法里的实际运用。

回答内容

模板方法模式定义了一个操作的算法骨架,把一些步骤的实现延迟到子类。在 Android 自定义 View 中,View 类提供了一系列生命周期方法,像 onMeasure()onLayout()onDraw() 等,这些构成了绘制 View 的算法骨架,开发者可重写这些方法实现特定逻辑。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;// 自定义圆形 View 类,继承自 View
public class CustomCircleView extends View {// 用于绘制的画笔对象private Paint paint;// 构造函数,接收上下文参数public CustomCircleView(Context context) {super(context);// 初始化画笔init();}// 初始化画笔的方法private void init() {// 创建一个新的画笔对象paint = new Paint();// 设置画笔颜色为蓝色paint.setColor(Color.BLUE);// 设置画笔样式为填充paint.setStyle(Paint.Style.FILL);}// 重写 onMeasure 方法,用于测量 View 的大小@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 期望的大小,可根据实际情况调整int desiredSize = 200;// 获取宽度的测量模式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.EXACTLY) {// 如果是精确模式,使用测量大小width = widthSize;} else if (widthMode == MeasureSpec.AT_MOST) {// 如果是最大模式,取期望大小和测量大小的最小值width = Math.min(desiredSize, widthSize);} else {// 如果是未指定模式,使用期望大小width = desiredSize;}// 根据高度的测量模式确定最终高度if (heightMode == MeasureSpec.EXACTLY) {// 如果是精确模式,使用测量大小height = heightSize;} else if (heightMode == MeasureSpec.AT_MOST) {// 如果是最大模式,取期望大小和测量大小的最小值height = Math.min(desiredSize, heightSize);} else {// 如果是未指定模式,使用期望大小height = desiredSize;}// 设置测量好的宽度和高度setMeasuredDimension(width, height);}// 重写 onDraw 方法,用于绘制 View 的内容@Overrideprotected void onDraw(Canvas canvas) {// 获取 View 宽度的一半,作为圆心的 x 坐标int centerX = getWidth() / 2;// 获取 View 高度的一半,作为圆心的 y 坐标int centerY = getHeight() / 2;// 取圆心 x 和 y 坐标的最小值作为半径int radius = Math.min(centerX, centerY);// 使用画笔在画布上绘制圆形canvas.drawCircle(centerX, centerY, radius, paint);}
}

从源码层面来看,View 类中的 onMeasure()onLayout()onDraw() 方法本身有默认实现,但这些实现可能不符合特定需求。例如,View 类的 onMeasure() 方法默认只是简单处理,没有考虑复杂的测量逻辑。自定义 View 时,重写这些方法就如同在模板方法模式中,子类根据自身需求实现父类定义的抽象步骤。CustomCircleView 类重写 onMeasure() 方法确定 View 的大小,重写 onDraw() 方法绘制圆形,父类控制算法结构,子类实现具体步骤,体现了模板方法模式。

面试题 2:在自定义 View 中如何运用策略模式实现不同的绘制效果

考点分析

该问题考查对策略模式的掌握,以及如何在自定义 View 中灵活切换不同的绘制策略。

回答内容

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。在自定义 View 中,可根据不同情况使用不同的绘制策略。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;// 绘制策略接口,定义了绘制的抽象方法
interface DrawingStrategy {// 在画布上进行绘制的方法,接收画布、画笔、宽度和高度作为参数void draw(Canvas canvas, Paint paint, int width, int height);
}// 矩形绘制策略类,实现了 DrawingStrategy 接口
class RectangleDrawingStrategy implements DrawingStrategy {// 实现绘制矩形的逻辑@Overridepublic void draw(Canvas canvas, Paint paint, int width, int height) {// 在画布上绘制矩形canvas.drawRect(0, 0, width, height, paint);}
}// 圆形绘制策略类,实现了 DrawingStrategy 接口
class CircleDrawingStrategy implements DrawingStrategy {// 实现绘制圆形的逻辑@Overridepublic void draw(Canvas canvas, Paint paint, int width, int height) {// 计算圆心的 x 坐标int centerX = width / 2;// 计算圆心的 y 坐标int centerY = height / 2;// 取圆心 x 和 y 坐标的最小值作为半径int radius = Math.min(centerX, centerY);// 在画布上绘制圆形canvas.drawCircle(centerX, centerY, radius, paint);}
}// 自定义形状 View 类,继承自 View
public class CustomShapeView extends View {// 当前使用的绘制策略private DrawingStrategy drawingStrategy;// 用于绘制的画笔对象private Paint paint;// 构造函数,接收上下文参数public CustomShapeView(Context context) {super(context);// 创建一个新的画笔对象paint = new Paint();// 设置画笔颜色为红色paint.setColor(Color.RED);// 设置画笔样式为填充paint.setStyle(Paint.Style.FILL);// 默认使用矩形绘制策略drawingStrategy = new RectangleDrawingStrategy();}// 设置绘制策略的方法public void setDrawingStrategy(DrawingStrategy drawingStrategy) {// 更新当前使用的绘制策略this.drawingStrategy = drawingStrategy;// 通知 View 重绘invalidate();}// 重写 onDraw 方法,用于绘制 View 的内容@Overrideprotected void onDraw(Canvas canvas) {// 获取 View 的宽度int width = getWidth();// 获取 View 的高度int height = getHeight();// 如果绘制策略不为空if (drawingStrategy != null) {// 调用当前绘制策略的 draw 方法进行绘制drawingStrategy.draw(canvas, paint, width, height);}}
}

从源码层面看,策略模式将不同的绘制算法封装在不同的策略类中,如 RectangleDrawingStrategy 和 CircleDrawingStrategyCustomShapeView 类通过持有 DrawingStrategy 接口的引用,实现了绘制策略的切换。当调用 setDrawingStrategy() 方法时,只需传入不同的策略对象,就可以改变绘制行为,而不需要修改 CustomShapeView 类的核心逻辑。这种设计使得代码的可维护性和扩展性得到了提高。

面试题 3:简述观察者模式在自定义 View 中的应用场景及实现方式

考点分析

此问题考查对观察者模式的理解,以及如何在自定义 View 中实现状态监听和通知机制。

回答内容

观察者模式定义了对象之间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知并更新。在自定义 View 中,可用于监听 View 的状态变化。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;import java.util.ArrayList;
import java.util.List;// 进度改变监听器接口,定义了进度改变时的回调方法
interface ProgressChangeListener {// 当进度改变时调用的方法,接收新的进度值作为参数void onProgressChanged(int progress);
}// 自定义进度条 View 类,继承自 View
public class CustomProgressBar extends View {// 当前的进度值private int progress;// 存储进度改变监听器的列表private List<ProgressChangeListener> listeners;// 用于绘制的画笔对象private Paint paint;// 构造函数,接收上下文参数public CustomProgressBar(Context context) {super(context);// 初始化进度为 0progress = 0;// 创建一个新的监听器列表listeners = new ArrayList<>();// 创建一个新的画笔对象paint = new Paint();// 设置画笔颜色为绿色paint.setColor(Color.GREEN);// 设置画笔样式为填充paint.setStyle(Paint.Style.FILL);}// 添加进度改变监听器的方法public void addProgressChangeListener(ProgressChangeListener listener) {// 将监听器添加到列表中listeners.add(listener);}// 移除进度改变监听器的方法public void removeProgressChangeListener(ProgressChangeListener listener) {// 从列表中移除指定的监听器listeners.remove(listener);}// 设置进度的方法public void setProgress(int progress) {// 更新当前的进度值this.progress = progress;// 通知所有监听器进度已改变notifyListeners();// 通知 View 重绘invalidate();}// 通知所有监听器进度已改变的方法private void notifyListeners() {// 遍历监听器列表for (ProgressChangeListener listener : listeners) {// 调用每个监听器的 onProgressChanged 方法listener.onProgressChanged(progress);}}// 重写 onDraw 方法,用于绘制进度条@Overrideprotected void onDraw(Canvas canvas) {// 获取 View 的宽度int width = getWidth();// 获取 View 的高度int height = getHeight();// 根据当前进度计算进度条的宽度int progressWidth = (int) (width * ((float) progress / 100));// 在画布上绘制进度条canvas.drawRect(0, 0, progressWidth, height, paint);}
}

从源码层面来看,CustomProgressBar 类维护了一个 ProgressChangeListener 列表,当进度发生变化时,调用 notifyListeners() 方法遍历列表,通知所有监听器进度已改变。这类似于 Android 系统中 LiveData 的实现机制,LiveData 也是通过维护一个观察者列表,当数据发生变化时通知所有观察者。在自定义 View 中使用观察者模式,可以实现 View 状态变化的监听和响应,提高代码的可维护性和扩展性。

面试题 4:请说明组合模式在自定义 ViewGroup 中的体现

考点分析

该问题考查对组合模式的认识,以及如何在自定义 ViewGroup 中构建 “部分 - 整体” 的层次结构。

回答内容

组合模式将对象组合成树形结构以表示 “部分 - 整体” 的层次结构,用户对单个对象和组合对象的使用具有一致性。在 Android 中,ViewGroup 是组合模式的典型应用。

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;// 自定义线性布局 ViewGroup 类,继承自 ViewGroup
public class CustomLinearLayout extends ViewGroup {// 构造函数,接收上下文参数public CustomLinearLayout(Context context) {super(context);}// 重写 onLayout 方法,用于布局子 View@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// 获取子 View 的数量int childCount = getChildCount();// 当前子 View 的顶部位置int currentTop = 0;// 遍历所有子 Viewfor (int i = 0; i < childCount; i++) {// 获取当前子 ViewView child = getChildAt(i);// 获取子 View 的测量宽度int childWidth = child.getMeasuredWidth();// 获取子 View 的测量高度int childHeight = child.getMeasuredHeight();// 布局子 View 的位置child.layout(0, currentTop, childWidth, currentTop + childHeight);// 更新当前顶部位置currentTop += childHeight;}}// 重写 onMeasure 方法,用于测量子 View 和自身的大小@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 获取子 View 的数量int childCount = getChildCount();// 子 View 的总高度int totalHeight = 0;// 子 View 的最大宽度int maxWidth = 0;// 遍历所有子 Viewfor (int i = 0; i < childCount; i++) {// 获取当前子 ViewView child = getChildAt(i);// 测量子 View 的大小measureChild(child, widthMeasureSpec, heightMeasureSpec);// 累加子 View 的高度totalHeight += child.getMeasuredHeight();// 更新最大宽度maxWidth = Math.max(maxWidth, child.getMeasuredWidth());}// 设置自身的测量宽度和高度setMeasuredDimension(maxWidth, totalHeight);}
}

从源码层面看,ViewGroup 类本身就体现了组合模式的思想。ViewGroup 可以包含多个子 View 或 ViewGroup,形成一个树形结构。CustomLinearLayout 继承自 ViewGroup,重写 onMeasure() 方法测量子 View 的大小并确定自身大小,重写 onLayout() 方法布局子 View 的位置。用户可以像操作单个 View 一样操作 CustomLinearLayout,而不需要关心其内部子 View 的具体实现。这种设计使得代码的结构更加清晰,易于维护和扩展。

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

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

相关文章

【Scrapy】简单项目实战--爬取dangdang图书信息

目录 一、基本步骤 1、新建项目 &#xff1a;新建一个新的爬虫项目 2、明确目标 &#xff08;items.py&#xff09;&#xff1a;明确你想要抓取的目标 3、制作爬虫 &#xff08;spiders/xxspider.py&#xff09;&#xff1a;制作爬虫开始爬取网页 4、存储内容 &#xff08;p…

开源CMS系统的SEO优化功能主要依赖哪些插件?

在当今互联网时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;是网站获取流量的核心手段之一。开源内容管理系统&#xff08;CMS&#xff09;因其灵活性和丰富的插件生态&#xff0c;成为许多开发者和企业的首选。本文将以主流开源CMS为例&#xff0c;深入解析其SEO优…

在 JMeter 中使用 BeanShell 获取 HTTP 请求体中的 JSON 数据

在 JMeter 中&#xff0c;您可以使用 BeanShell 处理器来获取 HTTP 请求体中的 JSON 数据。以下是几种方法&#xff1a; 方法一&#xff1a;使用前置处理器获取请求体 如果您需要在发送请求前访问请求体&#xff1a; 添加一个 BeanShell PreProcessor 到您的 HTTP 请求采样器…

在 WSL (Windows Subsystem for Linux) 中配置和安装 Linux 环境

在 WSL (Windows Subsystem for Linux) 中配置和安装 Linux 环境 WSL 允许你在 Windows 上运行 Linux 环境&#xff0c;以下是详细的配置和安装指南。 1. 安装前的准备工作 系统要求 Windows 10 版本 2004 及更高版本(内部版本 19041 及更高版本)或 Windows 11 64 位系统 虚…

AlphaFold蛋白质结构数据库介绍

AlphaFold Protein Structure Database (AlphaFold DB) 是 DeepMind + EMBL-EBI 合作开发的公开蛋白质结构预测数据库,是利用 AlphaFold2/AlphaFold3 AI模型 预测的全基因组级蛋白质三维结构库。 网址: https://alphafold.ebi.ac.uk 项目内容主办单位DeepMind + EMBL-EBI上线…

3.2goweb框架GORM

GORM 是 Go 语言中功能强大的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;支持 MySQL、PostgreSQL、SQLite、SQL Server 等主流数据库。以下是 GORM 的核心概念和用法详解&#xff1a; ​​一、基础入门​​ 1. 安装 go get -u gorm.io/gorm go get -u gorm.io…

第三部分:特征提取与目标检测

像边缘、角点、特定的纹理模式等都是图像的特征。提取这些特征是许多计算机视觉任务的关键第一步&#xff0c;例如图像匹配、对象识别、图像拼接等。目标检测则是在图像中找到特定对象&#xff08;如人脸、汽车等&#xff09;的位置。 本部分将涵盖以下关键主题&#xff1a; …

Canvas基础篇:图形绘制

Canvas基础篇&#xff1a;图形绘制 图形绘制moveTo()lineTo()lineTo绘制一条直线代码示例效果预览 lineTo绘制平行线代码示例效果预览 lineTo绘制矩形代码示例效果预览 arc()arc绘制一个圆代码实现效果预览 arc绘制一段弧代码实现效果预览 arcTo()rect()曲线 结语 图形绘制 在…

瑞芯微芯片算法开发初步实践

文章目录 一、算法开发的一般步骤1.选择合适的深度学习框架2.对于要处理的问题进行分类&#xff0c;是回归问题还是分类问题。3.对数据进行归纳和整理4.对输入的数据进行归一化和量化&#xff0c;保证模型运行的效率和提高模型运行的准确度5.在嵌入式处理器上面运行模型&#x…

计算机毕业设计--基于深度学习(U-Net与多尺度ViT)的模糊车牌图像清晰化复原算法设计与实现(含Github代码+Web端在线体验链接)

基于深度学习的U-Net架构下多尺度Transformer车牌图像去模糊算法设计与实现 如果想对旧照片进行模糊去除&#xff0c;划痕修复、清晰化&#xff0c;请参考这篇CSDN作品&#x1f447; 计算机毕业设计–基于深度学习的图像修复&#xff08;清晰化划痕修复色彩增强&#xff09;算…

(Go Gin)Gin学习笔记(四)Gin的数据渲染和中间件的使用:数据渲染、返回JSON、浅.JSON()源码、中间件、Next()方法

1. 数据渲染 1.1 各种数据格式的响应 json、结构体、XML、YAML类似于java的properties、ProtoBuf 1.1.1 返回JSON package mainimport ("github.com/gin-gonic/gin""net/http" )func main() {r : gin.Default()r.POST("/demo", func(res *gi…

实验:串口通信

/************************************************* * AT89C52 串口通信实验&#xff08;实用修正版&#xff09; * 特点&#xff1a; * 1. 解决所有编译警告 * 2. 保持代码简洁 * 3. 完全功能正常 ************************************************/ #include <re…

智驾赛道的诺曼底登陆,Momenta上海车展雄起

作者 |芦苇 编辑 |德新 今年的上海车展依旧热闹非凡&#xff0c;但火热的车市背后也是暗流涌动。尤其对智驾供应商而言&#xff0c;「智驾平权」带动了解决方案大量上车&#xff0c;各大主机厂纷纷选定各自的主要供应商&#xff0c;这也意味着赛道机会越发收敛。 正如汽车品牌…

Java 事务详解

目录 一、事务的基本概念1.1 什么是事务?1.2 事务的 ACID 特性二、Java 事务管理的实现方式2.1 JDBC 事务管理2.2 Spring 事务管理2.2.1 添加 Spring 依赖2.2.2 配置 Spring 事务管理2.2.3 使用 Spring 事务注解三、事务隔离级别四、最佳实践4.1 尽量缩小事务范围4.2 合理选择…

DirectX12(D3D12)基础教程七 深度模板视图\剔除\谓词

本章主要讲遮挡&#xff0c;作者认为比较复杂有难度的知识点&#xff0c;作为基础教程不会深入讲解。 GPU渲染管线 主要包括以下阶段 输入装配&#xff08;IA&#xff09;&#xff1a;读取顶点数据 &#xff0c;定义顶点数据结构顶点着色&#xff08;VS&#xff09;&#xf…

温补晶振(TCXO)稳定性优化:从实验室到量产的关键技术

在现代通信、航空航天、5G基站等对频率稳定性要求极高的领域&#xff0c;温补晶振&#xff08;TCXO&#xff09;扮演着不可或缺的角色。其稳定性直接影响系统的性能与可靠性&#xff0c;因此&#xff0c;对TCXO稳定性优化技术的研究与实践至关重要。 一、温度补偿算法&#xff…

C++,设计模式,【建造者模式】

文章目录 通俗易懂的建造者模式&#xff1a;手把手教你造电脑一、现实中的建造者困境二、建造者模式核心思想三、代码实战&#xff1a;组装电脑1. 产品类 - 电脑2. 抽象建造者 - 装机师傅3. 具体建造者 - 电竞主机版4. 具体建造者 - 办公主机版5. 指挥官 - 装机总控6. 客户端使…

前端基础之《Vue(13)—重要API》

重要的API 一、nextTick() 1、写法 Vue.$nextTick()或者this.$nextTick() 原因&#xff1a; set操作代码是同步的&#xff0c;但是代码背后的行为是异步的。set操作修改声明式变量&#xff0c;触发re-render生成新的虚拟DOM&#xff0c;进一步执行diff运算&#xff0c;找到…

Windows 中搭建 browser-use WebUI 1.4

目录 1. 背景介绍2. 搭建过程3. 补充 1. 背景介绍 背景&#xff1a;想要在 Windows 中复现 browser-use WebUI pickle反序列化漏洞&#xff0c;该漏洞在 v1.7 版本中已经修复&#xff0c;所以需要搭建 小于 1.7 版本的环境&#xff0c;我这里搭建的是 1.4 版本。 项目地址&am…

【数据通信完全指南】从物理层到协议栈的深度解析

目录 1. 通信技术演进与核心挑战1.1 从电报到5G的技术变迁1.2 现代通信系统的三大瓶颈 2. 通信系统架构深度解构2.1 OSI七层模型运作原理2.2 TCP/IP协议栈实战解析 3. 物理层关键技术实现3.1 信号调制技术演进路线3.2 信道复用方案对比 4. 数据传输可靠性保障4.1 CRC校验算法数…