android view设置按钮颜色_Android 自定义View篇(四)自定义属性详解

f06f21e50d397996515929860e00686b.png

作者:宋者为王

连接:https://cnblogs.com/andy-songwei/p/10979161.html

前言


尽管 Android 系统提供了不少控件,但是有很多酷炫效果仍然是系统原生控件无法实现的。好在 Android 允许自定义控件,来弥补原生控件的不足。但是在很多初学者看来,自定义 View 似乎很难掌握。其中有很大一部分原因是我们平时看到的自定义 View 使用中,有多种形式,有的寥寥数笔,有的逻辑很复杂,有的直接继承 View 或 ViewGroup,有的却直接继承系统的原生控件,有的可以直接使用系统定义的属性,而有的却自定义了自己的属性。

实际上实现自定义 View 的方式,从整体上看,只分为三种:组合控件,继承控件,自绘控件。然后就是根据需要来添加自定义的属性,就这么简单。

一、组合控件

组合控件,顾名思义,就是将系统原有的控件进行组合,构成一个新的控件。这种方式下,不需要开发者自己去绘制图上显示的内容,也不需要开发者重写 onMeasure,onLayout,onDraw 方法来实现测量、布局以及 draw 流程。所以,在实现自定义 view 的三种方式中,这一种相对比较简单。

实际开发中,标题栏就是一个比较常见的例子。因为在一个 app 的各个界面中,标题栏基本上是大同小异,复用率很高。所以经常会将标题栏单独做成一个自定义 view,在不同的界面直接引入即可,而不用每次都把标题栏布局一遍。本节就自定义一个标题栏,包含标题和返回按钮两个控件,来介绍这种组合控件的实现方式。

1、定义标题栏布局文件

定义标题栏的布局文件 custom_title_view.xml,将返回按钮和标题文本进行组合。这一步用于确定标题栏的样子,代码如下所示:

<?xml  version="1.0" encoding="utf-8"?>

2、根据给定布局实现自定义 View

public 

为了编译理解和记忆,这里对该部分做一点说明:

  1. 代码中对外提供了两个接口,一是动态设置标题,二是使用者可以自定义返回按钮的点击事件。

  2. CustomTitleView 的构造函数,要选择两个参数的,选择其它参数的构造函数会报错。这一点是笔者开发机测试的结果,暂时不清楚是不是所有手机上都是这样。

  3. 这里是继承的 FrameLayout,但是继承 LinearLayout,RelativeLayout 等系统布局控件都可以。之所以要继承这些系统现成的 ViewGroup,是因为这样可以不用再重写 onMeasure,onLayout 等,这样省事很多。由于这里是一个布局控件,要用 LayoutInflater 来填充,所以需要继承 ViewGroup,如果继承 View 的直接子类,编译会不通过。所以,CustomTitleView 自己就是一个容器,完全可以当成容器使用,此时 CustomTitleView 自身的内容会和其作为父布局添加的子控件,效果会叠加,具体的叠加效果是根据继承的容器特性决定的。

3、在 Activity 的布局文件中添加 CustomTitleView

在 Activity 的布局文件 activity_custom_view_compose_demo.xml 中,像使用系统控件一样使用 CustomTitleView 即可。前说了,CustomTitleView 自己就是继承的现成的系统布局,所以它们拥有的属性特性,CustomTitleView 一样拥有。

<?xml  version="1.0" encoding="utf-8"?>

4、在 Activity 中操作 CustomTitleView

public 

获取到 CustomTitleView 实例,设置标题文字,然后自定义"Back"按钮点击事件 setLeftOnClickListener()。

5、效果图

按照如上的 4 步,就通过组合控件完成了一个比较简单的自定义标题栏。可见,这种方式是非常简单的。

ac5e7645e03ccf6518987b1f8bc48c68.png

二、继承控件

通过继承系统控件(View 子类控件或 ViewGroup 子类控件)来完成自定义 View,一般是希望在原有系统控件基础上做一些修饰性的修改,而不会做大幅度的改动,如在 TextView 的文字下方添加下划线,在 LinearLayout 布局中加一个蒙板等。这种方式往往都会复用系统控件的 onMeasure 和 onLayout 方法,而只需要重写 onDraw 方法,在其中绘制一些需要的内容。下面会分别继承 View 类控件和 ViewGroup 类控件来举例说明。

1、继承 View 类系统控件

如下示例为在 TextView 文字下方显示红色下划线,其基本步骤如下:

(1)继承 View 控件,并重写 onDraw 方法

@SuppressLint(

(2)在布局文件中调用

就像使用一个普通 TextView 一样使用 UnderlineTextView。

<?xml  version="1.0" encoding="utf-8"?>

(3)效果图

fcfb1a6adda3b5211b7e207890a2ff6c.png

2、继承 ViewGroup 类系统控件

如下示例演示,在 layout 布局上添加一个浅红色的半透明蒙板,这种需求在工作中也是非常常见的。

(1)继承 ViewGroup 类系统控件

public 

(2)在布局文件中调用

对 ForegroundLinearLayout 的使用,就和使用其父类 LinearLayout 一样。

<?xml  version="1.0" encoding="utf-8"?>

(3)效果图

在宽为全屏宽度,高为 200dp 的布局范围内,绘制完子其子控件 TextView 后,在上面覆盖了一层浅红色的半透明蒙板。

c6566d8625fe1fbbbc2664517a20417e.png

从上面两个例子可见,继承系统原有的控件来实现自定义 View,步骤非常简单,比组合控件简单多了。但是这一节需要对 Canvas,paint 等绘制方面的知识有一定的了解,且还需要对 ViewGroup 的中内容的绘制顺序有一定的了解,才能在原生控件的基础上做出想要的效果来。

三、自绘控件

这三种方法中,自绘控件是最复杂的,因为所有的绘制逻辑和流程都需要自己完成。采用自绘控件这种方式时,如果自定义 View 为最终的叶子控件,那么需要直接继承 View;而不过自定义 View 为容器类控件,则需要直接继承 ViewGroup。这里依然针对直接继承 View 和 ViewGroup 分别举例进行说明。

1、自绘叶子 View 控件

这里通过画一个直方图来展示自绘 View 控件的实现。

(1)直接继承 View 类

自绘叶子 View 控件时,最主要工作就是绘制出丰富的内容,这一过程是在重写的 onDraw 方法中实现的。由于是叶子 view,它没有子控件了,所以重写 onLayout 没有意义。onMeasure 的方法可以根据自己的需要来决定是否需要重写,很多情况下,不重写该方法并不影响正常的绘制。

public 

(2)在 Activity 界面的布局文件中引入

和其它自定义控件一样,直接在布局文件中引入即可。

<?xml  version="1.0" encoding="utf-8"?>

(3)效果图

6dbdb7e8dfd88a974a075ddbefdc2240.png

2、自绘 ViewGroup 控件

这里通过自定义一个父布局控件,并添加一个子 view 来作为例子讲解该方法的实现。

(1)直接继承 ViewGroup 类

自绘 ViewGroup 控件,需要直接继承 ViewGroup,在该系列第一篇文章中将绘制流程的时候就讲过,onLayout 是 ViewGroup 中的抽象方法,其直接继承者必须实现该方法。所以这里,onLayout 方法必须要实现的,如果这里面的方法体为空,那该控件的子 view 就无法显示了。要想准确测量,onMeasure 方法也是要重写的。下面例子中,只演示了第一个子 view 的测量和布局,onLayout 方法中的 child.layout,就完成了对子 view 的布局。

public 

(2)在布局文件中和普通父布局一样被引入

<?xml  version="1.0" encoding="utf-8"?>

(3)效果图

50fa896b5df96aab4942f23abd390a70.png

上述代码中 android:layout_centerInParent="true"没有起效,从布局上看 TextView 应该是处于屏幕的正中央,但是实际结果却还是在左上方显示。这是因为 CustomLayout 控件,并没有实现 android:layout_centerInParent 这个属性,所以是无效的。关于属性的问题,正是下一节要介绍的内容。

四、在自定义 View 中使用自定义属性

我们在使用 Android 原生控件的时候,经常可以看到在布局文件中可以设置很多的属性值,如:

<TextViewandroid:id="@+id/title_tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="Title"android:textColor="@android:color/white"android:textSize="20sp" />

这里可以根据需要随时设置 TextView 要显示的文字,文字颜色,文字大小等各种属性,给使用者带来了极大的方便。我们在使用自定义 View 的时候,也非常希望能够像 TextView 等系统原生控件一样通过设置属性值来个性化自定义 View。本节咱们在上一节自定义直方图的基础上,来介绍自定义属性的基本使用流程。

1、在 values 中编写需要的属性

在 res/values/下新建资源文件,这里咱们命名为 attrs.xml,在其中编写所需要的属性

<?xml  version="1.0" encoding="utf-8"?>

这里"declare-styleable"中的 name 是自行命名的,可以理解为这个自定义属性集合的名称。代码中包含了两个自定义属性,名称分别为"textColor"和"histogramColor",这里用来设置直方图中文字的颜色和直方图的颜色。format 表示的是属性的格式,这里均设置为"color",表示对应的属性是用来设置颜色值的。对于"format",后面还会详细讲到。其它的就是固定的格式了,直接套用就行。

2、在自定义 View 中引入属性

public 

将上述代码和前面第三节中自绘直方图代码对比,红色部分是修改或新增的代码。初始化属性的地方,这个过程需要在构造函数中完成。其中,和自定义属性集建立联系,获取开发者在布局文件中使用时设置的相应属性值,如果没有设置,则会使用默认设置的颜色,分别为 Color.BLACK 和 Color.GREEN,用完后一定要回收资源。这样就初始化了文字颜色 mTextColor 值和 mHistogramColor 值,在后面 onDraw 中就使用该值来绘制对应的部分。

3、在布局文件中设置属性值

<?xml  version="1.0" encoding="utf-8"?>

这段代码中,第 3,10,11 行和以往的布局文件有些不一样,这是使用自定义属性时的固定格式。第 3 行中,如果布局文件中没有这一句,一定要加上,这句是声明命名空间,只有声明了命名空间才能使用自定义属性。"app"是该命名空间的名称,这里是自行命名的,不一定非要用"app"。第 10 行和 11 行,"app:attrName"表示用的是自定义的属性,固定用法,前面 mTextColor 和 mHistogramColor 值就是从这里获取的。

4、效果图

1a8013f332e3b2d8c257c1d8e82b47cc.png

五、自定义属性格式汇总

在上面一节中,仅仅只是对文字颜色和直方图颜色的属性值做了设置,是为了演示自定义属性的使用步骤。在实际开发中,完全可以定义更多类型的属性,如显示文字的内容,文字的大小,直方图的宽度等。format 也不只限定于"color",还有"String","Integer"等,多种多样。本节就汇总一下平时比较常用的一些属性 format。

1、常用的 11 种 format 类型

<?xml  version="1.0" encoding="utf-8"?>

如上列出了平时工作中在常见的 11 种类型的格式,说是 11 种,但最后一种是前面 10 种的组合而已。看到上述的属性名称应该很熟悉吧,都是系统原生控件的属性名称。

2、使用举例

如下对上述属性的使用一一举例演示,可以对照着来理解,都是平时常用的系统控件。

总结

关于自定义 View 的 3 中实现方式以及自定义属性的使用,这里就讲完了。读完后,是不是发现基本的实现流程其实非常简单。当然,本文为了说明实现流程,所以举的例子都比较简单,但不是说绘制内容也一样简单。就好像办理入学手续很简单,但读书这件事却不那么容易一样。要完成一些酷炫的自定义 View,还需要好好地掌握 Canvas,Paint,Path 等工具的使用,以及 View 的绘制流程原理。

2f6728394d4ed9a1fdb5342a758447f0.gif

Android 自定义View篇(一)View绘制流程 Android 自定义View篇(二)Canvas详解 Android 自定义View篇(三)Paint详解

d3acefafd41a3e483aeac9fdb40610fb.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值