原文地址:http://android.xsoftlab.net/training/custom-views/index.html

引言

Android框架含有大量的View类,这些类用来显示各式各样的数据,并可以直接与用户交互。但是某些时候,APP有一项很特殊的需求,但是框架中的View还不能满足这样的需求,这时就需要根据需要自己创建一个全新的View类了。这节课程将会学习如何创建这样的自定义View。

创建View类

一个设计良好的自定义View与其它任何设计良好的View类都很相似。它封装了一系列特殊的功能,并将简单易用的接口暴露了出来。它高效、合理的使用了CPU及内存等资源。除了要实现上面这些特点之外,自定义View还需要:

  • 遵循Android标准。
  • 提供可以工作于Android XML布局中的自定义样式属性。
  • 发送可访问事件。
  • Android平台的兼容性。

Android框架提供了一系列的基础类及XML标签来辅助你创建符合以上标准的View。这节课将会学习如何使用Android框架来创建自定义View的核心功能。

创建View的子类

Android中的所有View类都继承于View。自定义View可以直接继承View,也可以继承View子类(比如Button)。

为了使Android Developer Tools可以与你的View产生交互,应当至少提供一个含有Context与AttributeSet作为参数的构造方法。这个构造方法可以使布局编辑器创建或编辑View的实例。

class PieChart extends View {public PieChart(Context context, AttributeSet attrs) {super(context, attrs);}
}

定义自定义属性

如果要往UI中添加View,你需要以XML元素的形式指定该View,并通过元素属性控制View的行为与外貌。定义良好的自定义View还可以通过XML添加、设计这些样式。为了使自定义View拥有以下这些行为,你必须:

  • 在< declare-styleable >资源元素中定义自定义View的属性。
  • 在XML布局中指定属性的值。
  • 在运行时接收属性值。
  • 将接收到的属性值应用到View中。

这部分将会学习如何定义属性及如何指定它们的值。下部分会学习在运行时如何处理接收并使用这些值。

要定义自定义属性,需要在工程中添加< declare-styleable >资源。通常会将这些资源放在res/values/attrs.xml文件中。下面是一个attrs.xml文件的示例:

<resources><declare-styleable name="PieChart"><attr name="showText" format="boolean" /><attr name="labelPosition" format="enum"><enum name="left" value="0"/><enum name="right" value="1"/></attr></declare-styleable>
</resources>

上面这段代码声明了两个自定义属性,showText 和 labelPosition,它们都属于一个名为PieChart的风格实体。风格实体的名字按照惯例与对应的自定义View的类名相一致。尽管不是必须要遵循这项惯例,但很多受欢迎的代码编辑者都喜欢依照这项命名惯例来提供实现声明。

一旦定义了自定义属性,你就可以像内置属性那样在XML文件中使用它们。唯一的不同就是,自定义属性属于不同的命名空间。它们不属于标准的http://schemas.android.com/apk/res/android命名空间,而属于http://schemas.android.com/apk/res/[your package name]。举个例子,下面是如何使用自定义属性的示例:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews"><com.example.customviews.charting.PieChart
     custom:showText="true"custom:labelPosition="left" />
</LinearLayout>

为了避免重复定义命名空间,示例中使用了xmls指令。该指定使http://schemas.android.com/apk/res/com.example.customviews命名空间与custom别名产生了关联。你可以为命名空间使用任何你想使用的名称。

注意,这里在布局中引用的自定义View采用的是自定义View的权限定名。如果View类是个内部类,还必须通过外部类的类名进一步限定。举个例子, PieChart含有一个名叫PieView的内部类。如果要为这个类使用自定义属性,你应该使用标签:com.example.customviews.charting.PieChart$PieView.

应用自定义属性

当一个View从XML布局中被创建后,XML标签中的所有属性都会被读取,并通过View的构造方法以AttributeSet的形式传递到View中。尽管它可能是直接从AttributeSet中读取数据的,但是它还是有一些缺点:

  • 资源所引用的属性值不能够被解析
  • 不支持Style

相反的,可以将AttributeSet传给obtainStyledAttributes()方法。该方法会返回一个TypedArray对象,它内部包含了被间接引用的数组值。

Android资源编译器为了使使用obtainStyledAttributes()方法更加简便做了大量的工作。在资源目录中的每一个资源都会在R.java中定义相应的属性id。你可以使用这预定义的常量去TypedArray中读取属性。下面是PieChart类如何读取属性的示例:

public PieChart(Context context, AttributeSet attrs) {super(context, attrs);TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.PieChart,0, 0);try {mShowText = a.getBoolean(R.styleable.PieChart_showText, false);mTextPos = a.getInteger(R.styleable.PieChart_labelPosition, 0);} finally {a.recycle();}
}

注意TypedArray是一个共享资源,必须在使用完之后对其进行回收。

添加属性及事件

Attributes是控制View的外观与行为的一种强大的方式,但是它只有在View初始化的时候才会被读取。如果要提供动态的行为,则需要暴露相应的get,set方法。下面的代码展示了PieChart是如何暴露名为showText的属性方法的:

public boolean isShowText() {return mShowText;
}
public void setShowText(boolean showText) {mShowText = showText;invalidate();requestLayout();
}

注意在setShowText中调用了invalidate()方法与requestLayout()方法。这些方法可以确保View的行为更改生效。在更改完成属性之后不得不重新绘制该View,这样才能使View的外观生效。这样系统才会知道该View需要重新绘制。同样的,如果新属性值可能会引起尺寸或者形状的更改还需要请求新的布局。忘记调用这些方法会引起很难发现的Bug.

自定义View还应当支持事件监听器,以便与重要的事件交互。比如,PieChart暴露一个名为OnCurrentItemChanged的自定义事件,用来通知监听器用户旋转了饼图。

很容易忘记暴露属性和事件,尤其你是唯一一个自定义View的用户。在定义View接口时多花点心思可以在将来维护的时候少花点时间和精力。一个良好的习惯就是总是暴露任何成员属性的外观与行为的属性方法。

可访问性

自定义View应当支持更宽泛的用户。这其中包括视力有缺陷的残疾人。为了支持这部分用户的使用,应当:

  • 使用android:contentDescription属性标识你的输入字段
  • 在适当的时候通过sendAccessibilityEvent()方法发送可访问事件
  • 支持更多的控制器,比如D-pad及轨迹球

有关更多信息请参见 Making Applications Accessible。


阅读完本篇文章之后,可以继续阅读下一篇文章:Android官方开发文档Training系列课程中文版:创建自定义View之View的绘制

Android官方开发文档Training系列课程中文版:创建自定义View之View的创建相关推荐

  1. Android官方开发文档Training系列课程中文版:后台服务之IntentService的创建

    原文地址:http://android.xsoftlab.net/training/run-background-service/index.html 引言 除非特别指定,否则所有的操作都是在UI线程 ...

  2. Android官方开发文档Training系列课程中文版:目录

    原文地址 : http://android.xsoftlab.net/training/index.html 引言 在翻译了一篇安卓的官方文档之后,我觉得应该做一件事情,就是把安卓的整篇训练课程全部翻 ...

  3. Android官方开发文档Training系列课程中文版:OpenGL绘图之图形绘制

    原文地址:http://android.xsoftlab.net/training/graphics/opengl/draw.html 如果你还不清楚如何定义图形及坐标系统,请移步:Android官方 ...

  4. Android官方开发文档Training系列课程中文版:使用Fragment构建动态UI之Fragment创建

    原文地址:http://android.xsoftlab.net/training/basics/fragments/index.html 导言 为了在Android中创建动态的多面板用户界面,你需要 ...

  5. Android官方开发文档Training系列课程中文版:打印内容之HTML文档打印

    原文地址:http://android.xsoftlab.net/training/printing/html-docs.html 在Android中打印内容要比打印照片要复杂一些,它要求将文本与图像 ...

  6. Android官方开发文档Training系列课程中文版:动画视图之转场框架介绍

    原文地址:http://android.xsoftlab.net/training/transitions/index.html 引言 Activity所呈现的UI经常会由用户的输入或者其它事件而发生 ...

  7. Android官方开发文档Training系列课程中文版:调用相机之控制相机

    原文地址:http://android.xsoftlab.net/training/camera/cameradirect.html 在这节课,我们会讨论如何使用Android框架API来直接控制相机 ...

  8. Android官方开发文档Training系列课程中文版:Android的安全建议

    原文地址:http://android.xsoftlab.net/training/articles/security-tips.html Android系统内置的安全策略可以有效的降低应用程序的安全 ...

  9. Android官方开发文档Training系列课程中文版:后台加载数据之使用CursorLoader进行查询

    原文地址:http://android.xsoftlab.net/training/load-data-background/index.html 引言 在ContentProvider中查询数据是需 ...

最新文章

  1. 使用动态内表——ALV输出
  2. Qt工作笔记-QTreeWidget中itemAt中的坑
  3. MiniDao_1.6-SNAPSHOT 版本发布,轻量级Java持久化框架
  4. chk mysql.sh_zabbix监控mysql_MySQL
  5. Odoo 强大的开源微信模块 oejia_wx
  6. 浅谈BeanDefinition、BeanDefinitionMap、RootBeanDefintion三者的关系
  7. 数字小人时钟windows电脑屏幕保护
  8. c#生成二维码,一维码(条形码)
  9. 小赛毛游C记——初识C语言(1)
  10. [vue3.x]实战问题--Extraneous non-props attributes
  11. HTML5+CSS3小实例:发光文字悬停特效
  12. 从网上下载一个vue项目,跑起来的全过程
  13. Java基础 项目实例五 简易聊天系统
  14. 网页制作:一个简易美观的登录界面
  15. how2j离线资源,2018,12月26最新
  16. 地平线创始人兼CEO余凯:自动驾驶处理器——人工智能的珠穆朗玛
  17. 图像语义分割网络FCN(32s、16s、8s)原理及MindSpore实现
  18. teradata ttu_Teradata Studio中文乱码解决方法
  19. IPD-产品需求管理过程(2)
  20. 如何调用通达信l2行情接口?

热门文章

  1. 速度之王 — LZ4压缩算法与其他算法的比较
  2. Linux Cpu 利用率计算
  3. 尘埃落定,初心未改——一个大学生的电子大赛感悟
  4. pthread 的坑
  5. mysql sqlserver分页_SqlServer、MySql万能分页代码
  6. JavaScript高级之ECMASript 7、8 、9 、10 新特性
  7. jQuery学习笔记系列(一)——入口函数,jQuery对象和DOM对象,jQuery选择器、样式操作、效果(显示隐藏、滑入滑出、淡入淡出、自定义动画、停止动画队列)
  8. LeetCode 2190. 数组中紧跟 key 之后出现最频繁的数字
  9. LeetCode 1718. 构建字典序最大的可行序列(贪心+回溯)
  10. LeetCode 网易-2. 古老的游戏机