创建自定义view

一个设计良好的的自定义view应该是一个设计良好的class,它包含了很多实用的功能,让人们更加容易使用接口。它充分利用GPU与内存的性能等等。 另外作为一个设计良好的类,一个自定义view还应该有以下特性:

  • 遵从android标准

  • 提供可以在layout中使用的自定义属性

  • 兼顾各种人士需求(比如视力,听力)

  • 兼容各种android平台版本

android的sdk提供了一系列的基础的类和xml的标记来帮助你创建一个满足你需求的自定义view。本节课将讨论如何利用android的framwork来创建一个有基本核心功能的自定义view。

继承一个view


android系统framwork层的view都是继承自View这个基类。你的自定义view也可以直接继承自View,或者你为了节省时间可以继承一个已经存在的子类,比如Button。

为了让Android Developer Tools 能和你的自定义view交互,你必须最少提供一个接受Context和AttributeSet为参数的构造函数。通过这个构造函数,layout编辑器可以创建和编辑你的自定义view的实例。(也就是可以在未运行的时候,展示出界面)

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

定义自定义的属性

为了向你的界面中添加一个内建的view,你需要在xml元素里面指定,然后通过元素的属性控制它的显示和行为。为了做到这一点,你必须:

  • <declare-styleable>资源属性下为你的自定义view定义属性

  • 在xml layout中指定属性的值

  • 在运行的时候,接受属性的值

  • 将接受的值应用到你的view中去

这一节讨论了如何定义自定义的属性与指定他们的值。下一节将处理在运行时接收与应用属性的值。

为了定义自定义属性,添加<declare-styleable>资源到你的工程中。通常我们会将这些资源放到res/values/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>

上面的代码声明了两个自定义属性,showtextlablePosition,这两个属性属于styleable 实体,命名为PieChart,styleable实体的命名通常为了方便,和你的自定义view的名字一样。尽管这不是一个严格的规定,但是很多非常流行的开源代码的作者也是遵从这个原则。

一旦你定义了自定义属性,你就可以像内置的android属性那样来运用你的属性。唯一的不同就是你的自定义属性是属于一个不同的命名空间的。他们不是属于http://schemas.android.com/apk/res/android这个命名空间,而是属于http://schemas.android.com/apk/res/[your package name]这个命名空间。例如,下面是如何使用PieChart的属性:

<?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>

为了避免重复这么长的命名空间,上面的例子使用了一个xmlns指示符。这个指示符把custom这个名字赋值给了http://schemas.android.com/apk/res-auto这个命名空间。 你可以选择任何的同名简化单词来替代你的命名空间。

Note:如果你没有使用gradle来构建你的系统,你的xlmns URI不能包含 res-auto 。这个URI比较包含完整的你的项目的名字。这个例子中,如果不是grale构建的话,URI应该为http://schemas.android.com/apk/res/com.example.customviews

请注意你在xml中指定的你的自定义view的名字。这个名字必须是这个类完整的类路径。如果你的自定义view是一个inner class,你必须讲outer class的名字也加上。例如,这个PieChart类如果有一个inner class 叫PieView.为了使用这个自定义view的属性,你应该这样写你的tag com.example.customviews.charting.PieChart$PieView

属性值的应用

当一个view从xml layout中创建出来后,所有的在xml tag中的属性就会从resourse bundle中读取出来并且传递给view的构造函数的参数AttributeSet.尽管我们可以直接从AttributeSet中读取属性值,但是这样做有一些缺点。

  • 资源的引用的属性值没有被分解出来

  • Styles没有被应用到属性值上

于是,我们把AttrbuteSet传递给obtainStyledAttributes()这个函数。这个函数会返回一个TypedArray,这个一系列的值,经过了解引用,同时将主题样式应用到值上。

Android的资源编译器在你调用obtainStyledAttributes()之前,做了很多工作。遍历res目录中<declare-styleable>资源的时候,生成了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对象是一个共享的资源,所以每次使用完毕后,请及时调用recycle方法。

添加类属性与事件

xml的属性是一个很强大的控制view显示与行为的方式,但是它们却只能在view初始化的时候来读取。为了提供动态的行为,我们可以为每一个xml属性提供get与set方法。下面代码片段展示了如何向外部提供一个get与set接口:

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

注意下,setShowText方法调用了invalidate()与requestLayout().这些调用很重要,是用来保证view的行为是可靠的。当你修改了一些可能影响view显示的属性时,你必须invalidate你的view,这样系统就可以知道这个view需要重新绘制。同样的,当你修改了一些影响view大小与形状的属性时,你必须调用requestLayout。忘记调用这个函数,可能到导致很多难以发现的bug。

自定义view也应该支持一些事件的监听。例如,PieChart向外提供一个叫做 OnCurrentItemChanged方法,来通知监听者用户已经旋转了pie chart。

我们很容易就忘记向外提供属性与事件监听,尤其是当这个自定义view只有我们一个人使用的时候。花一些时间来定义这些view的接口,这样可以节省以后维护的成本花费。一个好的做法就是,将所有影响显示与行为的属性都向外提供接口。

定义可接受性

你的自定义view应该尽可能支持更多的用户。包括视力,或者行动不方便的人士。为了支持这些人,你应该:

  • 在你的输入性的控件上面使用 android:contentDescription这个属性

  • 在合适的时间通过调用sendAccessiblityEvent发送兼容性事件

  • 支持交叉输入控制,比如轨迹球,D-pad

更多的关于创建兼容view的知识,请查看 Making Application Accessible

创建自定义view(翻译 androidtraining)的更多相关文章

  1. Android 创建自定义 View 的属性 (attrs) 时需要注意的问题

    自定义 View 的属性并不难,可以参照官方的文档 https://developer.android.com/training/custom-views/create-view.html 但是需要注 ...

  2. Android 自定义view(二) —— attr 使用

    前言: attr 在前一篇文章<Android 自定义view -- attr理解>已经简单的进行了介绍和创建,那么这篇文章就来一步步说说attr的简单使用吧 自定义view简单实现步骤 ...

  3. [原] Android 自定义View步骤

    例子如下:Android 自定义View 密码框 例子 1 良好的自定义View 易用,标准,开放. 一个设计良好的自定义view和其他设计良好的类很像.封装了某个具有易用性接口的功能组合,这些功能能 ...

  4. Android自定义View的套路

    一.自定义View的流程 1.属性设置 在styles.xml中设置控件属性,如果你想直接harcode可以忽略这步 <!--name为声明的"属性集合"名,可以随便取,但是 ...

  5. Android开发自定义View

    Android中View组件的作用类似于Swing变成中的JPanel,它只是一个空白的矩形区域,View组件中没有任何内容.对于Android应用的其他UI组件来说,它们都继承了View组件,然后在 ...

  6. 无废话Android之listview入门,自定义的数据适配器、采用layoutInflater打气筒创建一个view对象、常用数据适配器ArrayAdapter、SimpleAdapter、使用ContentProvider(内容提供者)共享数据、短信的备份、插入一条记录到系统短信应用(3)

    1.listview入门,自定义的数据适配器 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/and ...

  7. 【Android Training UI】创建自定义Views(Lesson 1 - 创建一个View类)

    发布在我的网站 http://kesenhoo.github.io/blog/2013/06/30/android-training-ui-creating-custom-views-lesson-1 ...

  8. 扩展JMeter - 创建自定义函数 - String Joiner (翻译)

    JMeter是测试自动化社区中最好的开源工具之一.它提供了所有可能的扩展,可以快速提供我们的测试脚本.为了让我们的生活更轻松,它还让我们通过实现几个接口来提出我们自己的插件. 在本文中,让我们看看如何 ...

  9. Android自定义View创建流程

    Android的framework提供了很多高质量的view,有时业务需求需要自定义View,其实现流程大致如下: 1.在values/attrs.xml中定义支持的自定义属性,示例如下:

随机推荐

  1. C#中Array、ArrayList和List三者的区别

    1.Array  在C#中最早出现的.在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也很简单. 它的空间大小是固定的,空间不够时也不能再次申请,所以需要事前确定合适的空间大小. 2. ...

  2. Asp.Net MVC 开发技巧(二)

    Linq查询 Linq的使用大体分为两种:语句表达式   和  方法 首先,我们要在控制器中定义好context private ApplicationDbContext db = new Appli ...

  3. 4星|《助推(实践版)》:英国政府用AB测试检验政策效果的经验

    助推:小行动如何推动大变革(实践版)(诺贝尔经济学奖得主理查德•塞勒的助推实践) 作者作为学者说服英国政府实施助推策略的经过,提到一些具体主推策略. 所谓的助推,很像IT业流行的AB测试,对政策的执行 ...

  4. OpenCV&&python_图像平滑(Smoothing Images)

    Goals 学习用不同低通滤波方法模糊图像(Blur imagess with various low pass filter) 用用定制的滤波器处理图像(Apply custom-made filt ...

  5. Analysis of Algorithms

    算法分析 Introduction 有各种原因要求我们分析算法,像预测算法性能,比较不同算法优劣等,其中很实际的一条原因是为了避免性能错误,要对自己算法的性能有个概念. 科学方法(scientific ...

  6. Spring MVC面试整理

    Spring MVC执行过程 客户端的请求提交到dispatcherServlet DispatcherServlet查询一个或者多个handlermapping ,找请求的Controller Di ...

  7. python面向对象之类成员

    面向对象编程: OOP编程是利用类和对象来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得简单,并可以大大提高程序开发效率.另外,基于面向对象的程序可 ...

  8. python内置模块(三)

    hashlib模块 通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示). Python2中使用hashlib: import hashlib m = hashlib ...

  9. 劳动节前得空半天-总结一下最近使用的LINUX命令

    一.搜索文件 1.locate xxx.log   全盘搜索xxx.log文件 2.which java       查找命令 3.ll  xxx.log         在目录下查找文件 二.搜索内 ...

  10. 【CSS】关于flex

    flex 属性用于设置或检索弹性盒模型对象的子元素如何分配空间. 如果元素不是弹性盒模型对象的子元素,则 flex 属性不起作用. 设为Flex布局以后,子元素的float.clear和vertica ...