Android 自定义View(一):View是什么?如何创建自定义view,自定义属性等

目录

1)View是什么?
2)View分类
3)View的知识点
4)View的工作流程是怎么样的?
5)案例:如何自定义View?比如我们要实现一个输入框带有清除按钮的view
6)疑问:宽高怎么样理解,xy这些?
7)如何开发自定义属性?比如X图标,我想更换成其他图标

一、View是什么?


在 Android 中,View 是用户界面基本构建块之一,View类是Android中各种组件的基类,如View是ViewGroup基类。它是一个可见的矩形区域,用于显示应用程序中的内容和与用户进行交互。View 可以包含其他 View 或 ViewGroup,并且可以具有自己的属性、样式和行。

Android中的UI组件都由View、ViewGroup组成。

Android 提供了许多内置的 View 类,如 TextView(文本视图)、Button(按钮)、ImageView视图)等。

二、View分类


单一视图: 即一个View,如TextView, 不包含子View
视图组: 即多个View组成的ViewGroup,如LinearLayout, 包含子View

三、View的知识点


  1. 交互:触摸(TouchEvent)、动画(Animation)

  2. 封装:尺寸(measure)、属性(attributes)

  3. 绘图:Canvas、Paint

  4. 性能:OnDraw,Sufaceview(副线程绘图)


四、View的工作流程是怎么样的?


  1. 调用 setContentView() 方法设置布局或在 XML 布局文件中定义视图层次结构。
  2. 系统会解析布局文件并创建相应的 View 对象,形成一个视图树(View Hierarchy)。
  3. 在 Activity 或 Fragment 的生命周期方法中调用 onCreate()onStart 和 onResume()` 方法后,系统会开始绘制视图。
  4. 系统从根视图开始遍历整个视图树,并依次调用每个 View 的 draw() 方法进行绘制。
  5. draw() 方法中,View 会先绘制自身的内容,然后递归地绘制它的子视图。
  6. 绘制过中,系统会将每个 View 的绘制结果保存到一个称为 Canvas 的画布对象中。
  7. 最后,系统将 Canvas 中的绘制结果显示在屏幕上。

注意:在绘制过程中,系统还会对视图进行测量(measure)和布局(layout)操作,以确定每个视图的大小和位置。这些操作通常在 onMeasure()onLayout() 方法中完成。

请注意,以上流程仅涵盖了基本的 View 绘制流程,实际情况可能因特定需求而有所不同。

五、如何自定义View?比如我们要实现一个输入框带有清除按钮的view


如下是我们想要实现的一个view
在这里插入图片描述
当android内置view无法满足我们的时候,我们需要自定义View。那么我们应该如何自定义?如何绘制呢?接下来,我们会通过这个案例进行讲解。

package com.example.mymediaplayer.myviewimport android.content.Context
import android.content.ContextParams
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.widget.EditText
import androidx.core.content.ContextCompat
import com.example.mymediaplayer.Rclass MyEditText @JvmOverloads constructor(//第一步:继承EditTextcontext: Context, attrs: AttributeSet? = null
) : androidx.appcompat.widget.AppCompatEditText(context, attrs) {private val TAG = "MyEditText"private val iconDrawable = ContextCompat.getDrawable(context, R.drawable.baseline_clear_24)init {//直接设置显示出来x。drawableRight}override fun onTextChanged(text: CharSequence?,start: Int,lengthBefore: Int,lengthAfter: Int) {super.onTextChanged(text, start, lengthBefore, lengthAfter)//第二步:当文字发生改变的时候,则调用这个方法,进行图标的显示toggleCleanIcon()}override fun onTouchEvent(event: MotionEvent?): Boolean {
//第四步:触摸的时候,并且坐标是在图标上面,才进行文字的删除。event?.let {e->iconDrawable?.let {if (e.action ==MotionEvent.ACTION_UP&& e.x>width -it.intrinsicWidth&& e.x<width&& e.y >height/2 -it.intrinsicHeight/2&& e.y <height/2 +it.intrinsicHeight/2){text?.clear()//直接调用清除了,不需要什么点击事件去监听。使用触摸事件。}}}return super.onTouchEvent(event)
}override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) {super.onFocusChanged(focused, direction, previouslyFocusedRect)//第三步:获得焦点的时候才需要显示toggleCleanIcon()}//是否显示private fun toggleCleanIcon(){val icon = if(isFocused && text?.isNotEmpty()==true)iconDrawable else nullLog.d(TAG, "toggleCleanIcon: "+icon)//用于设置视图(EditText)的四个方向上的可绘制对象(Drawable)。如下就是通过传入右侧的 Drawable 对象来显示在文本视图的右边。setCompoundDrawablesRelativeWithIntrinsicBounds(null,null,icon,null)}
}

代码解释:
1)因为我们做的是一个EditText,所以我们需要继承EditText来自定义一个新的view,那么继承EditText就需要重写他的工作构造方法。
2)当输入框有文字的时候,我们想显示一个清理图标在输入框的右边,所以我们需要重写onTextChanged方法去监听,当有文字的时候则调用setCompoundDrawablesRelativeWithIntrinsicBounds方法去设置一个drawable。因为我们本身是在EditText里面,所以我们可以直接调用setCompoundDrawablesRelativeWithIntrinsicBounds方法。
3)并且我们想,输入框获得焦点的时候才显示清理图标,如果失去焦点,那么就消失。
4)在触摸离开清理图标并且触摸的坐标是在icon的时候,则将文本清空。

疑问:宽高怎么样理解,xy这些?

在这里插入图片描述

override fun onTouchEvent(event: MotionEvent?): Boolean {
//第四步:触摸的时候,并且坐标是在图标上面,才进行文字的删除。event?.let {e->iconDrawable?.let {if (e.action ==MotionEvent.ACTION_UP&& e.x>width -it.intrinsicWidth&& e.x<width&& e.y >height/2 -it.intrinsicHeight/2&& e.y <height/2 +it.intrinsicHeight/2){text?.clear()//直接调用清除了,不需要什么点击事件去监听。使用触摸事件。}}}return super.onTouchEvent(event)
}

比如这一段代码,e.x就是起点位置,width是获取控件的宽度,intrinsicWidth则是获取控件的固有宽度,例如,一个ImageView的固有宽度可能是其图片的实际宽度,而一个TextView的固有宽度则可能取决于其文本内容的长度和字体大小。

比如一个输入框的宽度是300,而清除图标的宽度是40,那么e.x>width -it.intrinsicWidth的范围则是图标开始的位置,再加上e.x<width就形成了清除图标的一个宽度。也就是260~300.
在这里插入图片描述
e.y >height/2 -it.intrinsicHeight/2,为什么要除以2呢,105除以2=52.5,36除以2=13,52.5-13=39,就在图标的顶部,e.y <height/2 +it.intrinsicHeight/2,就是65这个位置,就是36的一般加上去。

除以2的操作是为了进行中心对齐的考量,确保比较的是中心点而不是边缘或其他位置。
在这里插入图片描述

七、如何开发自定义属性?比如X图标,我想更换成其他图标

(1)首先我们要创建一个attrs.xml文件

在这里插入图片描述

(2)然后我们为自定义控件创建自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="MyEditText"><attr name="clenIcon" format="reference"/></declare-styleable>
</resources>

(3)在自定义控件里面读取这个属性并进行设置。

class MyEditText @JvmOverloads constructor(//实现EditTextcontext: Context, attrs: AttributeSet? = null
) : androidx.appcompat.widget.AppCompatEditText(context, attrs) {private val TAG = "MyEditText"private var iconDrawable = ContextCompat.getDrawable(context, R.drawable.baseline_clear_24)init {context.theme.obtainStyledAttributes(attrs,R.styleable.MyEditText,0,0).apply {try {val iconId = getResourceId(R.styleable.MyEditText_clenIcon,0)if (iconId!=0) {iconDrawable = ContextCompat.getDrawable(context,iconId)}}finally {recycle()}}}...
  1. context.theme.obtainStyledAttributes(…):
    (1)这行代码通过context(通常是当前视图所在的上下文,如Activity或Fragment)和theme(当前主题的引用)来获取一个TypedArray对象。这个对象允许你访问在XML布局文件中为该视图指定的自定义属性。
    (2)attrs参数是一个AttributeSet对象,它包含了视图在XML中定义的所有属性。
    (3)R.styleable.MyEditText是一个指向资源文件中定义的自定义属性集的引用。这个资源文件(通常位于res/values/attrs.xml)定义了可以在XML布局文件中使用的自定义属性。
    (4)后面的两个0参数分别是主题资源的ID和布尔值,用于指定是否强制使用默认样式。这里都设置为0,表示不使用特定的主题资源,并且不强制使用默认样式。

  2. val iconId = getResourceId(R.styleable.MyEditText_clenIcon, 0)尝试从自定义属性集中获取名为clenIcon的属性值

  3. finally { recycle() }:无论是否成功读取和设置了图标,finally块中的recycle()方法都会被调用。这是为了释放TypedArray对象占用的资源,避免内存泄漏。recycle()方法是TypedArray类的一部分,用于在不再需要该对象时释放其资源。

(4)使用自定义属性

<com.example.mymediaplayer.myview.MyEditTextandroid:layout_width="200dp"android:layout_height="wrap_content"android:layout_marginTop="212dp"android:hint="请输入"app:clenIcon="@android:drawable/ic_delete"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.498"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" />

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

【GaussDB(DWS)】数仓部署架构与物理结构分析

数仓架构与物理结构分析 一、部署架构二、物理结构三、测试验证 一、部署架构 华为数据仓库服务DWS&#xff0c;集群版本8.1.3.x 集群拓扑结构&#xff1a; 上述拓扑结构为DWS单AZ高可靠部署架构&#xff0c;为减少硬件故障对系统可用性的影响&#xff0c;建议集群部署方案遵…

计算机网络408考研 2018

1 计算机网络408考研2018年真题解析_哔哩哔哩_bilibili

RabbitMq如何确保消息不丢失

问题&#xff1a;在生产环境中由于一些不明原因&#xff0c;导致 rabbitmq 重启&#xff0c;在 RabbitMQ 重启期间生产者消息投递失败&#xff0c;导致消息丢失&#xff0c;需要手动处理和恢复。于是&#xff0c;我们开始思考&#xff0c;如何才能进行 RabbitMQ 的消息可靠投递…

【SQL】产品销售分析 I

目录 题目 分析 代码 题目 销售表 Sales&#xff1a; -------------------- | Column Name | Type | -------------------- | sale_id | int | | product_id | int | | year | int | | quantity | int | | price | int | ---------------…

基于Hadoop的超市进货推荐系统设计与实现【springboot案例项目】

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍系统分析系统设计数据表设计表4-1&#xff1a;关于我们表4-2&#xff1a;用户表4-3&#xff1a;管理员表表4-4&#xff1a;token表表4-5&#xff1a;系统简介表4-6&#xff1a;收藏…

Typro + PicGo 图床 + Docsify + GitHub Pages,玩转个人知识库搭建,写给小白的建站入门课

自动开了这个号以后&#xff0c;陆陆续续写了很多干货文章&#xff0c;一方面是可以帮助自己梳理思路&#xff0c;另一方面也方便日后查找相关内容。 但是&#xff0c;我想检索某个关键词是在之前哪篇文章写过的&#xff0c;就有点捉急了。CSDN 还好&#xff0c;可以检索到相关…

【实现100个unity特效之19】使用ShaderGraph实现Unity 2D水

最终效果 文章目录 最终效果前言开始新增无光照影响的shaderGraph半透明效果&#xff0c;并且有一些颜色的变化其他办法参考完结 前言 先粗略记录一下&#xff0c;后面再补充 开始 我们新建一个render texture 设置尺寸 然后我要创建另外一个摄像机&#xff0c;将他的画面…

el-tree自定义节点内容

<el-tree :data"data" :props"defaultProps" ref"treeRef" show-checkbox check-change"handleCheckChange"><!-- 自定义节点内容 --><template #default"{ node, data, store }"><span class"tr…

想实现ubuntu搭建sqli-labs靶场

目录 首先前期的nginx和php部署完成​编辑​编辑 Xftp导入sqli-labs 遇到了的问题 它提示我们请检查db-creds.inc 去尝试解决这个问题 尝试修改MySQL root密码 修改db-creds.inc配置 再次尝试依旧失败 思考&#xff1a;会不会是MySQL版本过高的原因 重新下载MySQL5.7.…

突破 ES 引擎局限性在用户体验场景中的优化实践

回顾&#xff1a;ES 慢上游响应问题优化在用户体验场景中的实践-CSDN博客 上文介绍了用户体验管理平台&#xff08;简称 VoC&#xff09;在针对 ES 慢上游响应场景下的优化实践&#xff0c;本文继续介绍针对第二个痛点问题——ES 引擎局限性的性能优化实践进行介绍。 下文以搜…

SSM美美电影院选座订票微信小程序-计算机毕业设计源码15838

美美电影院选座订票微信小程序 摘 要 美美电影院选座订票微信小程序是一个集在线选座和购票于一体的平台&#xff0c;旨在为用户提供便捷的观影体验。该小程序以其实时更新的座位图和多样化的支付方式而受到用户的喜爱。 首先&#xff0c;美美电影院选座订票微信小程序提供了直…

使用CLIP模型进行零样本图像分类的分步指南

零样本学习允许AI系统对未明确训练过的类别进行图像分类,标志着计算机视觉和机器学习的重大进步。本文将介绍使用CLIP实现零样本图像分类的详细分步指南,从环境设置到最终的图像处理和分类。我们首先介绍零样本学习的概念及其在现代AI应用中的重要性。然后深入探讨CLIP模型的概…

PostgreSQL的学习心得和知识总结(一百五十)|[performance]更好地处理冗余 IS [NOT] NULL 限定符

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

低代码之殇

低代码的浪潮已经持续几年了&#xff0c;很多声音冒出来&#xff0c;其中最刺耳就是&#xff1a;低代码就是个伪命题&#xff0c;根本不可能用低代码开发业务系统&#xff0c;尤其是复杂的业务系统&#xff1b; 更有甚者&#xff0c;直接给给低代码贴了标签&#xff1a;骗子 …

linux常见性能监控工具

常用命令top、free 、vmsata、iostat 、sar命令 具体更详细命令可以查看手册&#xff0c;这里只是简述方便找工具 整体性能top,内存看free&#xff0c;磁盘cpu内存历史数据可以vmsata、iostat 、sar、iotop top命令 交互&#xff1a;按P按照CPU排序&#xff0c;按M按照内存…

trie算法

1、定义 高效的存储和查找字符串集合的数据结构 它的优点是&#xff1a;利用字符串的公共前缀来减少查询时间&#xff0c;最大限度地减少无谓的字符串比较&#xff0c;查询效率比哈希树高 2、构建 我们可以使用数组来模拟实现Trie树。 我们设计一个二维数组 son[N] [26] 来…

鸿蒙HarmonyOS开发:@Observed装饰器和@ObjectLink装饰器:监听嵌套类对象属性变化

文章目录 一、装饰器二、概述三、限制条件四、装饰器说明五、Toggle组件1、子组件2、接口3、ToggleType枚举4、事件 六、示例演示1、代码2、效果 一、装饰器 State装饰器&#xff1a;组件内状态Prop装饰器&#xff1a;父子单向同步Link装饰器&#xff1a;父子双向同步Provide装…

SpringBoot MybatisPlus selectOne的坑

目录 一、问题 二、问题解决 三、其他方法 一、问题 selectOne在查询多条数据时会报错&#xff0c;查询语句并不会加 limit 1。 One record is expected, but the query result is multiple records。 二、问题解决 在QueryWrapper上添加如下&#xff1a; QueryWrapper&…

支付宝开放平台竟出现一张神秘人脸!

前言 ​ 我因一个单子来到支付宝开放平台来。在将其加入书签的时候&#xff0c;我发现出现了个神秘的人脸 一张笑容明媚的脸&#xff0c;就是出现的时候不太对 正常的收藏网址 应该是显示对应log 就不继续找相关例子了 ​ 添加书签的页面&#xff0c;本该出现log的地方缺出现了…

VScode的环境编译器选择

按快捷键 Ctrl Shift P 选择即可