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

news2024/11/15 18:24:46

目录

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.myview

import 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.R

class MyEditText @JvmOverloads constructor(//第一步:继承EditText
    context: 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 null
        Log.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(//实现EditText
    context: 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.MyEditText
        android: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.coloradmin.cn/o/1982198.html

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

相关文章

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 免单统计(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题…

0805作业+梳理

一、作业&#xff1a; 代码&#xff1a; create.c #include<myhead.h> int main(int argc, const char *argv[]) {//创建一个有名管道文件if(mkfifo("./linux",0664)-1){perror("mkfifo linux error");return -1;}getchar();system("rm linux…

8.15 C++作业

输入一组字符&#xff0c;实现各字符的归类统计 #include <iostream> #include <string.h>using namespace std;namespace xiaoli {string str;int len; } using namespace xiaoli;int main() {getline(cin,str);//识别空格len str.size();int a0,b0,c0,d0,e0;fo…

x-cmd mod | x yq - 轻量级的 YAML、JSON、XML 处理器

目录 简介使用语法参数子命令x yq repl 简介 yq (YAML Query) 是一个轻量级的 YAML、JSON、XML 处理器&#xff0c;主要用于查询和提取 YAML 数据。 x yq 是基于 yq 命令、为提升 yq 使用体验而设计的增强模块&#xff0c;具体的增强性改动如下&#xff1a; 简化 yq 命令的安…

【GoodERP更新日志】增加模块 质检管理 处理来料检、发货检功能

开源项目GoodERP更新-2024年8月5日 本次提交合并增加的功能或解决的问题&#xff1a;增加 质量管理模块->增加来料质检、发货质检功能 提交前: 无 提交后: 1、按供应商来料&#xff0c;安排来料质检工作&#xff1b; 2、按销售订单&#xff0c;安排对计划发货商品进行…

比较推荐哪种可视耳勺?5大热门产品专业测评分享!

由于现在人们对健康生活越来越重视&#xff0c;可视耳勺成为了个护健康产品&#xff0c;受到了越来越多消费者的关注和喜爱。这种挖耳勺采用了先进的无线技术和高清摄像头&#xff0c;能够让人们更加清晰地观察自己耳内的状况&#xff0c;从而更加安全、有效地清洁耳朵。但同时…

封装组件之使用vue3封装简易Button按钮

1.新建Button.vue <template><button :class"buttonClass"><!-- 用于输入内容 --><slot></slot></button> </template> <script lang"ts" setup> import { computed } from vue; //定义类型 const props…

OpenGL投影矩阵

OpenGL Projection Matrix OpenGL投影矩阵

大模型检索增强生成RAG

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhlRAG简介 大模型检索增强生成(Retrieval-Augmented Generation,简称RAG)是一种结合了信息检索技术和语言生成模型的人工智能技术,主要用于增强大型语言模型(Large Language Models, LLMs)处理…

能见度监测站在机场中的应用

在繁忙的机场&#xff0c;每一个细节都关乎着飞行安全。其中&#xff0c;能见度作为关键的气象因素&#xff0c;直接影响着飞机的起降安全。为此&#xff0c;能见度监测站在机场中扮演着重要的角色。 能见度监测站利用先进的传感器技术&#xff0c;实时监测机场周边的能见度情况…

【医学图像】医学图像基础

目录 引言 医学成像常识 1. 正交投影面 2 医学图像种类 3 医学图像质量评价标准 3.1 图像对比度成因 3.2 对比度 3.3 空间分辨率 3.4 时间分辨率 3.5 信噪比 signal-to-noise ratio SNR 3.6 数字和模拟图像 4 医疗临床的性能 4.1 图像获取和感知 4.2 灵敏度和特异…

WEB服务器安全加固与检查

01.安全加固定义 什么是安全加固? 安全加固是实现信息系统安全的关键环节。通过安全加固&#xff0c;将在信息系统的网络层、主机层、软件层、应用层等层次建立符合安全需求的安全状态&#xff0c;并以此作为保证网络信息系统安全的起点。 安全加固是配置软件…

使用gitea私有仓库作为依赖

实际问题 由于公司团队使用gitea搭建了git私有仓库&#xff0c;在开发Go程序的时候会有一些公共代码&#xff0c;比如插件和主程序之间要共享接口和数据结构&#xff0c;所以就需要在gitea私有仓库中创建依赖仓库&#xff0c;然后其他仓库引用这个私有仓库作为依赖。 解决方案…

记录|LabVIEW从0开始【09~10】

目录 前言一、属性节点案例&#xff1a;Step1. 表格控件设置Step2. 下拉列表控制Step1~Step2 效果展示Step3. 编写事件分支分支1&#xff1a;前面板关闭&#xff1f;分支2&#xff1a;表格&#xff0c;鼠标按下创建分支创建表格引用获得单元格的2种位置。设置下拉框的位置下拉框…

【秋招笔试题】矿脉开采(树形DP)

此题直接按树形dp做即可&#xff0c;每次从0枚举到k转移状态 #include <iostream> #include <cstring> #include <algorithm>using namespace std; #define endl \n #define lson node << 1 #define rson node << 1 | 1 const int maxn 1e5 5…

未授权访问漏洞系列详解⑥!

JBoss未授权访问漏洞 JBoss是一个基于J2EE的开放源代码应用服务器&#xff0c;代码遵循LGPL许可&#xff0c;可以在任何商业应用中免费使用;JBoss也是一个管理EJB的容器和服务器&#xff0c;支持EJB1.1、EJB 2.0和EJB3规范。,默认情况下访问 http://ip:8080/jmx-console 就可以…

宠物空气净化器哪个牌子好?希喂、霍尼韦尔宠物空气净化器对比推荐

随着养宠物人群变多&#xff0c;现在打着宠物专用旗号的空气净化器也越来越多&#xff0c;但是很多空气净化器对宠物的效果&#xff0c;真的是只有宣传上和宠物有关&#xff0c;实际设计和效果上和宠物毫无关系。需要大家擦亮眼睛&#xff0c;多做功课&#xff0c;才能不被那些…

PXE+kickstart实现无人值守自动安装操作系统

PXEkickstart实现无人值守自动安装操作系统 让待安装系统的主机自动安装系统&#xff0c;并且自动的安装kickstart文件安装系统&#xff0c;不需要人工干预&#xff0c;直接自动化批量安装操作系统 文章目录 PXEkickstart实现无人值守自动安装操作系统在VMware虚拟机中进行操作…

Day19 标准IO的学习

标准IO 1.I input 输入 键盘 O output 输出 显示器 2.一般我们调用相关IO操作时必须调用stdio头文件库&#xff0c;其位置在/usr/include/stdio.h&#xff0c;linux系统中最高管理者是root。 stdio.h ~ stdio.c ~ libc.so ~ /usr/lib so动态库 3.…

56 函数递归调用

函数的递归调用是函数调用的一种特殊情况。递归函数就是一个调用自己的函数。 函数递归通常用来把一个大型的复杂问题层层转化为一个与原来问题本质相同但规模很小、很容易解决或描述的问题&#xff0c;只需要很少的代码就可以描述解决问题过程中需要的大量重复计算。 # 使用递…