Android自定义控件之自定义属性(二)

2023-11-04

前言:

      上篇介绍了自定义控件的基本要求以及绘制的基本原理,本篇文章主要介绍如何给自定义控件自定义一些属性。本篇文章将继续以上篇文章自定义圆形百分比为例进行讲解。有关原理知识请参考Android自定义控件之基本原理(一)这篇文章。

需求产生背景:

     为何要引入自定义属性?当Android提供的原生属性不能满足实际的需求的时候,比如我们需要自定义圆形百分比半径大小、圆形背景、圆形显示的位置、圆形进度的背景等等。这个时候就需要我们自定义属性了。

自定义属性步骤:

1.)在res/values文件下添加一个attrs.xml文件,如果项目比较大的话,会导致attrs.xml代码相当庞大,这时可以根据相应的功能模块起名字,方便查找,例如:登录模块相关attrs_login.xml
 
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RoundImageView">
        <attr name="borderRadius" />
        <attr name="type" />
    </declare-styleable>

</resources>
 
2.)如何声明一组属性

使用<declare-styleable name="PercentView"></declare-styleable>来定义一个属性集合,name就是属性集合的名字,这个名字一定要起的见名知意。

  <declare-styleable name="PercentView">
    <!--添加属性-->
   </declare-styleable>

然后就是定义属性值了,通过<attr name="textColor" format="color" /> 方式定义属性值,属性名字同样也要起的见名知意,format表示这个属性的值的类型,类型有以下几种:

  • reference:引用资源

  • string:字符串

  • Color:颜色

  • boolean:布尔值

  • dimension:尺寸值

  • float:浮点型

  • integer:整型

  • fraction:百分数

  • enum:枚举类型

  • flag:位或运算

基于上面的要求,我们可以定义一下百分比控件属性
 
    <declare-styleable name="PercentView">
        <attr name="percent_circle_gravity"><!--圆形绘制的位置-->
            <flag name="left" value="0" />
            <flag name="top" value="1" />
            <flag name="center" value="2" />
            <flag name="right" value="3" />
            <flag name="bottom" value="4" />
        </attr>
        <attr name="percent_circle_radius" format="dimension" /><!--圆形半径-->
        <attr name="percent_circle_progress" format="integer" /><!--当前进度值-->
        <attr name="percent_progress_color" format="color" /><!--进度显示颜色-->
        <attr name="percent_background_color" format="color" /><!--圆形背景色-->
    </declare-styleable>
 
3.)布局中如何使用
 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:lee="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.whoislcj.views.PercentView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_margin="10dp"
        android:background="@color/red"
        android:padding="10dp"
        lee:percent_background_color="@color/gray"
        lee:percent_circle_gravity="left"
        lee:percent_circle_progress="30"
        lee:percent_circle_radius="50dp"
        lee:percent_progress_color="@color/blue" />

</LinearLayout>
 

为属性集设置一个属性集名称,我这里用的lee,我这是因为实在想不起使用什么属性集名称了,建议在真正的项目中使用项目的缩写,比如微信可能就是使用wx。

4.)自定义控件中如何获取自定义属性

每一个属性集合编译之后都会对应一个styleable对象,通过styleable对象获取TypedArray typedArray,然后通过键值对获取属性值,这点有点类似SharedPreference的取法。

 
  TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PercentView);
    if (typedArray != null) {
        backgroundColor = typedArray.getColor(R.styleable.PercentView_percent_background_color, Color.GRAY);
        progressColor = typedArray.getColor(R.styleable.PercentView_percent_progress_color, Color.BLUE);
        radius = typedArray.getDimension(R.styleable.PercentView_percent_circle_radius, 0);
        progress = typedArray.getInt(R.styleable.PercentView_percent_circle_progress, 0);
        gravity = typedArray.getInt(R.styleable.PercentView_percent_circle_gravity, CENTER);
        typedArray.recycle();
     }
 
5.)完整示例
 
public class PercentView extends View {
    private final static String TAG = PercentView.class.getSimpleName();
    private Paint mPaint;
    private int backgroundColor = Color.GRAY;
    private int progressColor = Color.BLUE;
    private float radius;
    private int progress;
    private float centerX = 0;
    private float centerY = 0;
    public static final int LEFT = 0;
    public static final int TOP = 1;
    public static final int CENTER = 2;
    public static final int RIGHT = 3;
    public static final int BOTTOM = 4;
    private int gravity = CENTER;
    private RectF rectF;  //用于定义的圆弧的形状和大小的界限

    public PercentView(Context context) {
        super(context);
        init();
    }

    public PercentView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initParams(context, attrs);
        init();
    }

    public PercentView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initParams(context, attrs);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        rectF = new RectF();
    }

    private void initParams(Context context, AttributeSet attrs) {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        rectF = new RectF();
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PercentView);
        if (typedArray != null) {
            backgroundColor = typedArray.getColor(R.styleable.PercentView_percent_background_color, Color.GRAY);
            progressColor = typedArray.getColor(R.styleable.PercentView_percent_progress_color, Color.BLUE);
            radius = typedArray.getDimension(R.styleable.PercentView_percent_circle_radius, 0);
            progress = typedArray.getInt(R.styleable.PercentView_percent_circle_progress, 0);
            gravity = typedArray.getInt(R.styleable.PercentView_percent_circle_gravity, CENTER);
            typedArray.recycle();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        Log.e(TAG, "onMeasure--widthMode-->" + widthMode);
        switch (widthMode) {
            case MeasureSpec.EXACTLY://
                break;
            case MeasureSpec.AT_MOST:
                break;
            case MeasureSpec.UNSPECIFIED:
                break;
        }
        Log.e(TAG, "onMeasure--widthSize-->" + widthSize);
        Log.e(TAG, "onMeasure--heightMode-->" + heightMode);
        Log.e(TAG, "onMeasure--heightSize-->" + heightSize);
        int with = getWidth();
        int height = getHeight();
        Log.e(TAG, "onDraw---->" + with + "*" + height);
        centerX = with / 2;
        centerY = with / 2;
        switch (gravity) {
            case LEFT:
                centerX = radius + getPaddingLeft();
                break;
            case TOP:
                centerY = radius + getPaddingTop();
                break;
            case CENTER:
                break;
            case RIGHT:
                centerX = with - radius - getPaddingRight();
                break;
            case BOTTOM:
                centerY = height - radius - getPaddingBottom();
                break;
        }
        float left = centerX - radius;
        float top = centerY - radius;
        float right = centerX + radius;
        float bottom = centerY + radius;
        rectF.set(left, top, right, bottom);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        Log.e(TAG, "onLayout");
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(backgroundColor);
        // FILL填充, STROKE描边,FILL_AND_STROKE填充和描边
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawCircle(centerX, centerY, radius, mPaint);
        mPaint.setColor(progressColor);

        double percent = progress * 1.0 / 100;
        int angle = (int) (percent * 360);
        canvas.drawArc(rectF, 270, angle, true, mPaint);  //根据进度画圆弧
    }
}
 

运行结果:

根据不同的配置显示的两种效果

小结:

通过自定义属性可以达到自定义的控件也能像原生的控件一样实现可配置。但是在实际的项目开发中,像本文介绍的这种自定义控件使用频率并不是最高的,使用频率较高的是通过自定义一个组合控件的方式,来达到布局文件的复用,以减少项目维护成本以及开发成本,下篇文章将重点介绍如何自定义控件组合。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android自定义控件之自定义属性(二) 的相关文章

  • Flutter(一)之Flutter的的简单入门分析

    前言 Flutter诞生于2018年 谷歌出品 应该是属于最新的移动跨平台开发框架了 从React Native自身框架的一些问题导致的用户量降低后 有很多小伙伴便转战Flutter战场 Flutter作为最新的跨移动平台开发框架 自然是汲
  • 从微信授权登录到数据安全性的思考总结

    前置知识 微信授权登录过程和相关名词 access token code openid等 微信授权登录 大都是拉起微信授权页面 用户同意授权后 再跳到自己应用的绑定手机页面进行绑定手机的操作 绑定之后自动登录 会话就像不会过期一样 或者是过
  • Android-App的设计架构经验谈,终获offer

    前言 想要成为一名优秀的Android开发 你需要一份完备的知识体系 在这里 让我们一起成长为自己所想的那样 学算法真的很痛苦 虽然大数据现在很火 但找到适合自己定位的职业也未尝不是一种合理选择 投百度的经历非常坎坷 想写出来和大家分享一下
  • HackPorts – Mac OS X 渗透测试框架与工具

    HackPorts是一个OS X 下的一个渗透框架 HackPorts是一个 超级工程 充分利用现有的代码移植工作 安全专业人员现在可以使用数以百计的渗透工具在Mac系统中 而不需要虚拟机 工具列表 0trace 3proxy Air Au
  • 基于linux的调试技术

    虽然使用printk函数可以很方便的将消息写入日志文件或者控制台 但是大量使用printk函数频繁的操作日志文件或者控制台文件会严重影响到linux驱动的开发性能 因此 这就需要linux驱动在开发阶段使用printk函数输出消息 在正式发
  • android opengl es 总结

    什么是OpenGL ES OpenGL ES 为OpenGL for Embedded System的缩写 为适用于嵌入式系统的一个免费二维和三维图形库 为桌面版本OpenGL 的一个子集 OpenGL ES 定义了一个在移动平台上能够支持
  • Android高级工程师普遍进阶难题:遇到瓶颈我们该如何去提升自己?哪个方向

    不要抱怨 抱怨无济于事 只能带来负能量 最重要的是改变 7 坚持写博客和技术文章 多总结 多参与开源项目 8 选择一家好的有发展前途的公司陪其成长 当发现现在公司不能满足自己的成长和发展时 果断跳槽 因为人生毕竟最宝贵的是时间 特别是程序员
  • Android 更新UI方法的深度解析

    1 Handler public class SecondActivity extends Activity private static final int MSG WHAT 101 TextView tv Button btn priv
  • Android智能下拉刷新框架-SmartRefreshLayout

    框架 下拉刷新控件还能框架化 智能又怎么回事 二话不多少先上Demo效果图 咱们再来探个究竟 Github 传送门注意 本文仅仅是博客文章 主要用于项目介绍和宣传 由于发布时间关系 部分内容已经过期 详细使用文档请跳转 github Dem
  • Unity 移动端触摸屏操作

    Unity 触屏操作 当将Unity游戏运行到IOS或Android设备上时 桌面系统的鼠标左键可以自动变为手机屏幕上的触屏操作 但如多点触屏等操作却是无法利用鼠标操作进行的 Unity的Input类中不仅包含桌面系统的各种输入功能 也包含
  • Android Rom修改制作工具软件集合

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1 SIN2IMG 用于固件ftf中system sin的解包 下载地址 SIN2IMG rar 使用方法 将固件ftf文件用rar打开 解压出system sin文件 将
  • 移动端表格组件

    最近在vue开发移动端过程中 需要用到表格展示 经过多方面对比感觉这个不错 https www csdn net tags Mtjacg4sOTk1NDctYmxvZwO0O0OO0O0O htmlhttps www csdn net ta
  • Lottie动画概述,文末有彩蛋

    原生的动画效果有时候写起来会非常的复杂 要考虑到很多兼容和效果 Lottie动画专门为了解决这种烦恼而产生的 注 不仅是Lottie可以做到 另外一种库也可以做到将动画分成一帧一帧展示 它就是 android gif drawable 库
  • Flutter状态管理Provider,简单上手

    学习Flutter一段时间了 偶然看到大家都说状态管理 多数人都是用redux 对于一个Android开发人员来说之前根本没接触过 于是开始了解redux 之后又了解闲鱼推出的fish redux 然后又看到Vadaski发表的一系列关于F
  • Android declare-styleable:自定义控件的属性(attr.xml,TypedArray)的使用

    android 自定义属性类型的使用 转自 http www cnblogs com ufocdy archive 2011 05 27 2060221 html 做Android布局是件很享受的事 这得益于他良好的xml方式 使用xml可
  • IOS 访问系统粘贴板

    粘贴板提供了一种核心OS特性 用于跨应用程序共享数据 用户可以跨应用来复制粘贴 也可以设置只在本应用中复制粘贴用来保护隐私 UIPasteboard类允许访问共享的设备粘贴板以及内容 下面代码返回一般的系统粘贴板 它适合大多数一般的复制粘贴
  • UE4命令行使用,解释

    命令行在外部 从命令行运行编辑项目 1 导航到您的 LauncherInstall VersionNumber Engine Binaries Win64 目录中 2 右键单击上 UE4Editor exe 的可执行文件 并选择创建快捷方式
  • 史上最全的《Android面试题及解析》,赶紧收藏!

    写在文章前面的话 工欲行其事 必先利其器 英雄和侠客更需要宝剑助己成功 同样 在现代软件开发环境中 每个Android开发者都需要更好的工具 帮助我们增强功能 提高效率 在这个竞争激烈的行业中 只有优秀的工程师能够生存 需要我们能够为客户提
  • ios -Unity3D的EasyAR集成到已经有项目中。

    近期 在做AR这一块 用EasyAR集成到iOS端 由于现在到项目已经上线 下一版本要做一个AR功能 于是迫于需求需要 自己研究和翻阅读好多集成到资料 通过整理分出几个重要到模块 其中在这里指出Xcode9版本确实好坑 建议弃坑 该用稍微好
  • Android4.0 SDK功能详解

    我在eoe的论坛找到的 就复制过来了 跟大家分享一下 Android 4 0 平台API等级 14 Android 4 0 是一次重要的平台发布版 为用户和应用程序开发者增加了大量的新特性 在下面我们将讨论的所有新特性和API中 因为它将

随机推荐

  • Spring MVC Controller传递枚举值示例

    功能描述 本文将通过一个小示例 展示在请求参数中传递枚举值 枚举定义 角色类定义 public enum RoleEnum EMPLOYEE short 1 Employee MANAGER short 2 Manager private
  • echarts前后端交互数据_前后端交互技术有哪些

    我们都知道 一个完整的IT项目是由多个不同岗位的成员共同完成 包括UI设计 前端开发 后端开发 测试等 为了实现项目的完整性 前后端需要运用技术实现联通 不过 前后端交互技术有哪些 参加郑州Web前端培训班会学吗 且看小编的分析 目前常用的
  • Java常见算法(六)【省份数量- 分组算法:深度优先、广度优先、并查集 】

    文章目录 省份数量 经典的分组算法 1 深度优先遍历 2 广度优先 3 并查集 算法 实验源码 省份数量 经典的分组算法 https www bilibili com video BV1Jv411A7Ty p 34 比如现在有三个城市 A城
  • Ai-M61/62系列的固件烧录指导

    文章目录 前言 一 软硬件的准备 二 原始硬件接线 三 烧录软件的使用 联系我们 前言 本文介绍Ai M61 62系列模组 开发板的固件烧录 一 软硬件的准备 Ai M61 62系列模组或者开发板一个 Ai M61 62烧录软件 下载链接
  • 进程和计划服务管理

    一 进程和服务 服务 是在操作系统内部活依赖网络环境运行的一种软件组件提供特定的功能或服务 服务一般在后台运行 职责包括接受请求 处理数据 执行操作 服务可以是系统自带的 也可以是基于linux开发的应用程序 服务特点 1 服务可以通过端口
  • YouTube-8M: A Large-Scale Video Classification Benchmark

    Abstract Many recent advancements in Computer Vision are attributed to large datasets Open source software packages for
  • 基于Android studio 的rpg游戏大地图的绘制

    今天开始写第一篇博客 好激动呢 衷心希望自己能坚持下去 不说闲话了 我们马上开始 最近一直在做一个基于Android studio的rpg2D角色扮演游戏 虽然说这个游戏已经烂大街了 其中的逻辑也是有了很多准确的简便的解释 不过真正做起来还
  • 【c++迭代器模拟实现】

    目录 前言 一 STL初始 二 六大组件之迭代器 迭代器初始 迭代器的模拟实现 1 victor 正向迭代器 反向迭代器1 反向迭代器2 反向迭代器3 2 list 正向迭代器 反向迭代器 总结 前言 打怪升级 第52天 一 STL初始 什
  • Oracle如何查询和中止正在运行的JOB

    今天遇到一个问题 有一个JOB会一直不停的执行 不能按照设定的间隔来执行 通过查询相关资料发现原来如此 当一个oracle job运行时返回一个error时 oracle会再次设法执行它 第一次尝试是在一分钟后 第二次是在2分钟后 第三次是
  • 代码点和代码单元的简单理解

    简单来说 代码单元就是用来表示代码点的 char数据类型就是一个采用UTF 16编码表示Unicode码点的代码单元 那代码点是什么 就是在unicode编码中的每一个符号 在特殊符号没出现之前 每个unicode代码点 字符在内 可以用一
  • 数据结构【2019年408第41题】

    1 一个N长度的链表的为了按照题目的需求 我们观察可以发现可以将一个链表从中间分开然后逆置然后依次插入则我们大致的思路如下 1 将链表分为两段 L和L2 2 将L2逆置从顺的顺序变为反过来的顺序 3 将L和L2按照 L gt L2 gt L
  • 高通LK显示屏分辨率太大,下半部分显示异常-FB buff超了的问题

    问题解决 bootable bootloader lk include dev fbcon h define LOGO IMG OFFSET 12 1024 1024 改成 define LOGO IMG OFFSET 20 1024 10
  • 前端利用html2canvas+jspdf实现html转pdf

    公司业务的月报页面 要实现pdf下载 查了资料 大概有个方向 就是利用html2canvas把html转为图片 然后再生成pdf格式的文件实现了下载 核心代码 import html2canvas from html2canvas impo
  • @Async注解在springboot项目中的使用

    众所周知 Async注解是开启一个异步线程的执行 但在springboot项目中如何具体的使用这个注解 还需要一一分析 仔细研究如何能更好的使用 Async注解 1 在项目启动类上添加 EnableAsync注解 如果没有这个注解而仅仅只有
  • 虚拟机安装Ubuntu16.04详细步骤

    文章目录 系统下载 安装VMware 配置虚拟机 系统安装 系统下载 官方下载地址 https ubuntu com download 阿里云镜像 推荐 http mirrors aliyun com ubuntu releases 16
  • linux/vim 操作tips

    1 Linux查看物理CPU个数 核数 逻辑CPU个数 总核数 物理CPU个数 X 每颗物理CPU的核数 总逻辑CPU数 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 查看物理CPU个数 cat proc cpuinfo grep
  • 服务器部署redis和springboot整合redis详细步骤

    目录 redis服务器部署 在springboot项目中整合redis redis相关链接 文档 文件下载 阿里云服务器官网 云小站 专享特惠 云产品推荐 阿里云 redis服务器部署 购买阿里云服务器后 到控制台查看实例 获取公网IP 账
  • 蓝桥杯——方格填数(JAVA)

    题目 本题为填空题 只需要算出结果后 在代码中使用输出语句将所填结果输出即可 如下的 10个格子 填入 0 9 的数字 要求 连续的两个数字不能相邻 左右 上下 对角都算相邻 一共有多少种可能的填数方案 运行限制 最大运行时间 1s 最大运
  • 【全】正则表达式语法

    简单来说 正则表达式就是描述字符串的规则 其作用如下 1 校验数据的有效性 2 从文本中提取内容 3 文本内容替换 元字符 元字符即正则表达式中具有特殊含义的专用字符 主要分为5类 1 基础 任意字符 换行除外 d 任意数字 D 任意非数字
  • Android自定义控件之自定义属性(二)

    前言 上篇介绍了自定义控件的基本要求以及绘制的基本原理 本篇文章主要介绍如何给自定义控件自定义一些属性 本篇文章将继续以上篇文章自定义圆形百分比为例进行讲解 有关原理知识请参考Android自定义控件之基本原理 一 这篇文章 需求产生背景