自定义支持读取XML属性的View

在Android中,添加一个View很简单,简单的你可以简简单单地使用xml和一部分简单的java代码就可以搞定。 比如这样

linenos:false

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout>

Android Framework提供了这种便捷的xml布局方式,而且还可以支持从XML节点读取属性值。那么如果如何自定义View并且支持读取XML属性值呢。 下面开始尝试以一种很简单容易理解的方式介绍一下。

自定义View代码实现

比如我们自定义一个View,这个View继承自TextView,名称为ExTextView。这里我们创建简单的构造方法,仅仅包含Context和AttributeSet参数。这样我们就可以在布局编辑器中创建或者修改ExTextView的实例。

linenos:false ExTextView.java

1 2 3 4 5 6 7 8 9 10 11

package com.example.customviewwithxml; import android.content.Context; import android.util.AttributeSet; import android.widget.TextView; public class ExTextView extends TextView { public ExTextView(Context context, AttributeSet attrs) { super(context, attrs); } }

定义XML属性

在使用系统内置的View时,我们可以通过在XML布局文件中指定属性来控制View的样式和行为。一个优秀的View应该可以通过XML来添加并且设置样式。所以,要让你自定义的View做到上述功能,你需要做。

  • 通过<declare-styleable> 来定义自定义View的属性集。
  • 可以在布局文件中指定View的属性值。
  • 在程序运行时可以检索读取属性值。
  • 为View应用读取出来的属性值。

现在就为你的View添加<declare-styleable>来定义属性集哈。 其存放文件为 res/values/attrs.xml。以下为几个简单实例。

linenos:false attrs.xml

1 2 3 4 5 6 7 8 9

<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="enableOnPad" format="boolean" /> <attr name="supportDeviceType" format="reference"/> <declare-styleable name="ExTextView"> <attr name="enableOnPad"/> <attr name="supportDeviceType"/> </declare-styleable> </resources>

注意

  • <declare-styleable name="ExTextView">中ExTextView为样式实体的名字,例样式实体的名字没有特殊的限制,但是通常约定为View的类名。

布局中使用自定义View

一旦我们定义了属性值,我们可以想系统内置的属性值一样使用,唯一不同的是,自定义的属性值和系统提供的属于不同的名字空间。系统内置的属性归属于名字空间http://schemas.android.com/apk/res/android 而自定义的属性归属于名字空间http://schemas.android.com/apk/res/[your package name]

linenos:false activity_main.xml

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:droidyue="http://schemas.android.com/apk/res/com.example.customviewwithxml" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <com.example.customviewwithxml.ExTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World" droidyue:supportDeviceType="@array/support_device_types" droidyue:enableOnPad="true" /> </RelativeLayout>

读取XML属性值

当View从XML中被创建时,其所有标签的属性值都是以AttributeSet的对象从资源包中获取并传递。

为什么不直接读取AttributeSet,而是obtainStyledAttributes

  • 属性值中得资源引用不能解析
  • 样式不会应用到View

linenos:false ExTextView.java

1 2 3 4 5 6 7 8 9 10 11

public ExTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.getTheme().obtainStyledAttributes( attrs,R.styleable.ExTextView, 0, 0); int supportDevicesResId = a.getResourceId(R.styleable.ExTextView_supportDeviceType, 0); String[] supportDeviceTypes = context.getResources().getStringArray(supportDevicesResId); boolean enableOnPad = a.getBoolean(R.styleable.ExTextView_enableOnPad, false); Log.i(VIEW_LOG_TAG, "getAtrributeFromXml supportDeviceType=" + Arrays.toString(supportDeviceTypes) + ";enableOnPad=" + enableOnPad); a.recycle(); }

注意,TypedArray实例为公用资源,再次使用之前需要回收(recycle)。

延伸阅读

Create View

源码下载

百度云

其他

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android研究院

强大灵活的WebView代理库-PrimWeb

PrimWeb 是一个代理的WebView基于的 Android WebView 和 腾讯 x5 WebView,容易、灵活使用以及功能非常强大的库,提供了 W...

38430
来自专栏分享达人秀

手把手教你读懂源码,View的Touch事件传递流程详细剖析

继上一篇分析,今天我们来接着分析Activity的Touch事件是如何分发传递的。 都知道在Android中的事件主要包括三部分内容:分发事件d...

18070
来自专栏Vamei实验室

安卓第五夜 维纳斯的诞生

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

20830
来自专栏Phoenix的Android之旅

ListView的相关总结

回顾一下, ListView的使用其实非常简单, 只需要提供一个 UI,提供一个装载数据的 Adapter, 在 Adapter的 getView 方法里实现每...

11020
来自专栏Vamei实验室

安卓第六夜 凡高的自画像

在上一讲中,我已经制作了一个简单的Android应用。项目的主要文件包括: MainActivity.java activity_main.xml 在这一讲,我...

21970
来自专栏Android先生

Android DataBinding & MVVM

先说说两者的关系,DataBinding是一个实现数据和UI绑定的框架,而MVVM是一种架构模式,实现MVVM模式需要借助DataBinding来完成。

14110
来自专栏知识分享

Android之TCP服务器编程android 之TCP客户端编程

推荐一个学java或C++的网站http://www.weixueyuan.net/,本来想自己学了总结出来再写博客,现在没时间,打字太慢!!!!,又想让这好东...

94060
来自专栏Android机动车

MVP模式的经典封装

说到MVP,大家应该都不陌生了,由于其高度解等等优点,越来越多的项目使用这个设计模式。然而,优点虽在,缺点也不少,其中一个就是类多了很多,而且V与P直接要项目通...

18120
来自专栏知识分享

8-51单片机ESP8266学习-AT指令(测试TCP服务器--51单片机程序配置8266,做自己的手机TCP客户端发信息给单片机控制小灯的亮灭)

http://www.cnblogs.com/yangfengwu/p/8776712.html 先把源码和资料链接放到这里 链接:https://pan.ba...

65920
来自专栏分享达人秀

ListActivity和自定义列表项

相信通过前两期的学习,以及会开发最简单的一些列表界面了吧,那么本期接着来学习更多方法技巧。 一、使用ListActivity 如果程序的窗口仅...

25250

扫码关注云+社区

领取腾讯云代金券