Android 中自定义控件和属性(attr.xml,declare-styleable,TypedArray)的方法和使用

本文转载自http://blog.csdn.net/jincf2011/article/details/6344678

今天我们的教程是根据前面一节扩展进行的,如果你没有看,请点击 Android高手进阶教程(三) 查看第三课,这样跟容易方便你的理解!

xml 文件里定义控件的属性,我们已经习惯了android:attrs="" ,那么我们能不能定义自己的属性能,比如:test:attrs="" 呢?答案是肯定的.

进入主题。大致以下步骤:

一、res/values 文件下定义一个attrs.xml 文件.代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <declare-styleable name="MyView">
  4. <attr name="textColor" format="color"/>
  5. <attr name="textSize" format="dimension"/>
  6. </declare-styleable>
  7. </resources>

二、 我们在MyView.java 代码编写如下,其中下面的构造方法是重点,我们获取定义的属性R.sytleable.MyView_textColor, 获取方法中后面通常设定默认值(float textSize = a.getDimension(R.styleable.MyView_textSize, 36 ); ) 防止我们在xml 文件中没有定义.从而使用默认值!

MyView 就是定义在<declare-styleable name="MyView "></declare-styleable> 里的 名字,获取里面属性用 名字_ 属性 连接起来就可以.TypedArray 通常最后调用 .recycle() 方法,为了保持以后使用该属性一致性!

  1. publicMyView(Context context,AttributeSet attrs)
  2. {
  3. super(context,attrs);
  4. mPaint = newPaint();
  5. TypedArray a = context.obtainStyledAttributes(attrs,
  6. R.styleable.MyView);
  7. inttextColor = a.getColor(R.styleable.MyView_textColor,
  8. 0XFFFFFFFF);
  9. float textSize = a.getDimension(R.styleable.MyView_textSize, 36);
  10. mPaint.setTextSize(textSize);
  11. mPaint.setColor(textColor);
  12. a.recycle();
  13. }

MyView.java MyView控件全部代码如下:

  1. packagecom.android.tutor;
  2. importandroid.content.Context;
  3. importandroid.content.res.TypedArray;
  4. importandroid.graphics.Canvas;
  5. importandroid.graphics.Color;
  6. importandroid.graphics.Paint;
  7. importandroid.graphics.Rect;
  8. importandroid.graphics.Paint.Style;
  9. importandroid.util.AttributeSet;
  10. importandroid.view.View;
  11. public class MyView extendsView {
  12. privatePaint mPaint;
  13. privateContext mContext;
  14. private static final String mString = "Welcome to Mr Wei's blog";
  15. publicMyView(Context context) {
  16. super(context);
  17. mPaint = newPaint();
  18. }
  19. publicMyView(Context context,AttributeSet attrs)
  20. {
  21. super(context,attrs);
  22. mPaint = newPaint();
  23. TypedArray a = context.obtainStyledAttributes(attrs,
  24. R.styleable.MyView);
  25. inttextColor = a.getColor(R.styleable.MyView_textColor,
  26. 0XFFFFFFFF);
  27. float textSize = a.getDimension(R.styleable.MyView_textSize, 36);
  28. mPaint.setTextSize(textSize);
  29. mPaint.setColor(textColor);
  30. a.recycle();
  31. }
  32. @Override
  33. protected voidonDraw(Canvas canvas) {
  34. // TODO Auto-generated method stub
  35. super.onDraw(canvas);
  36. //设置填充
  37. mPaint.setStyle(Style.FILL);
  38. //画一个矩形,前俩个是矩形左上角坐标,后面俩个是右下角坐标
  39. canvas.drawRect(new Rect(10, 10, 100, 100), mPaint);
  40. mPaint.setColor(Color.BLUE);
  41. //绘制文字
  42. canvas.drawText(mString, 10, 110, mPaint);
  43. }
  44. }

三、将我们自定义的MyView 加入布局main.xml 文件中,并且使用自定义属性,自定义属性必须加上:

" xmlns:test ="http://schemas.android.com/apk/res/com.android.tutor" ,test是自定义属性的前缀, com.android.tutor 是我们包名.

main.xml 全部代码如下:

  1. <?xml
  2. version="1.0" encoding="utf-8"?>
  3. <LinearLayout
  4. xmlns:android="http://schemas.android.com/apk/res/android"
  5. xmlns:test="http://schemas.android.com/apk/res/com.android.tutor"
  6. android:orientation="vertical"
  7. android:layout_width="fill_parent"
  8. android:layout_height="fill_parent"
  9. >
  10. <TextView
  11. android:layout_width="fill_parent"
  12. android:layout_height="wrap_content"
  13. android:text="@string/hello"
  14. />
  15. <com.android.tutor.MyView
  16. android:layout_width="fill_parent"
  17. android:layout_height="fill_parent"
  18. test:textSize="20px"
  19. test:textColor="#fff"
  20. />
  21. </LinearLayout>

四、运行之效果如下图:

Android 中自定义控件和属性(attr.xml,declare-styleable,TypedArray)的方法和使用

参考文章二:

Android 自定义View 己经不是什么新鲜话题,Android Api提供了一大堆基础组件给我们,需要什么特定功能还需要我们继承它们然后定制更加丰富的功能。前面有篇文章也说过为自定义VIEW添加属性,但只是一笔带过,这里就拿这点来说说吧。

第一种添加属性的方法,之前我也是经常使用这种写法,代码如下:

package com.terry.attrs;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

public class EditTextExt1 extends LinearLayout {

private String Text = "" ;

public EditTextExt1(Context context) {
this (context, null );
// TODO Auto-generated constructor stub
}

public EditTextExt1(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
int resouceId = - 1 ;

TextView tv
= new TextView(context);
EditText et
= new EditText(context);

resouceId
= attrs.getAttributeResourceValue( null , " Text " , 0 );
if (resouceId > 0 ) {
Text
= context.getResources().getText(resouceId).toString();
}
else {
Text
= "" ;
}
tv.setText(Text);

addView(tv);
addView(et,
new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
this .setGravity(LinearLayout.VERTICAL);

}

}
复制代码

这种写法,简单明了,不需要额外XML的配置,就可以在我们的VIEW文件下使用。

以上代码通过构造函数中引入的AttributeSet 去查找XML布局的属性名称,然后找到它对应引用的资源ID去找值。使用也时分方便。所以一直以来我也是很喜欢这种写法。

如上,自定好VIEW文件就可以在XML布局下如此使用:

< com.terry.attrs.EditTextExt1 android:id = " @+id/ss3 "
android:layout_width
= " wrap_content " android:layout_height = " wrap_content "
Text
= " @string/app_name " ></ com.terry.attrs.EditTextExt1 > 复制代码

好了,这是第一种为VIEW注册属性的写法,比较简单就不多介绍。

下面是第二为VIEW注册属性的写法,这里也要重点说说第二种注册 属性的写法和使用要点,先看一下JAVA代码要如何编写:

package com.terry.attrs;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

public class EditTextExt extends LinearLayout {

public EditTextExt(Context context) {
this (context, null );
// TODO Auto-generated constructor stub
}

public EditTextExt(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
int resouceId = - 1 ;
TypedArray typeArray
= context.obtainStyledAttributes(attrs,
R.styleable.EditTextExt);

TextView tv
= new TextView(context);
EditText et
= new EditText(context);

int N = typeArray.getIndexCount();
for ( int i = 0 ; i < N; i ++ ) {
int attr = typeArray.getIndex(i);
switch (attr) {
case R.styleable.EditTextExt_Oriental:
resouceId
= typeArray.getInt(R.styleable.EditTextExt_Oriental,
0 );
this .setOrientation(resouceId == 1 ? LinearLayout.HORIZONTAL
: LinearLayout.VERTICAL);
break ;
case R.styleable.EditTextExt_Text:
resouceId
= typeArray.getResourceId(
R.styleable.EditTextExt_Text,
0 );
tv.setText(resouceId
> 0 ? typeArray.getResources().getText(
resouceId) : typeArray
.getString(R.styleable.EditTextExt_Text));
break ;
}
}
addView(tv);
addView(et);
typeArray.recycle();

}

}
复制代码

如上代码,跟前面代码一样。还是用的一个EDITTEXT和TEXTVIEW做基础组件。下面我们一步步分析上面的代码:

R.styleable.EditTextExt 代码的是一个attrs指向的一个declare-styleable 的标签,如下代码:

<? xml version="1.0" encoding="UTF-8" ?>
< resources >
< declare-styleable name ="EditTextExt" >
< attr name ="Text" format ="reference|string" ></ attr >
< attr name ="Oriental" >
< enum name ="Horizontal" value ="1" ></ enum >
< enum name ="Vertical" value ="0" ></ enum >
</ attr >
</ declare-styleable >
</ resources > 复制代码

这个文件位于,values下的attrs.xml目录下面,我比较喜欢一个自定义View 对应一个declare-styleable标签。

Tip:一个自定义View 第一部分的代码,

TypedArray typeArray = context.obtainStyledAttributes(attrs,
R.styleable.EditTextExt);
复制代码

指定为一个declare-styleable,而在declare-styleable 下的attr (即各属性)Android 的ADT 将会自动生成为declare-styleable的name 名字加上“_”加上对应attr(即属性名称)的名称,如上(EditTextExt_Text)我们要得到Text 就需要R.styleable.EditTextExt_Text,这一点的话可以看看R.java生成文件:

public static final class styleable {
/** Attributes that can be used with a EditTextExt.
<p>Includes the following attributes:</p>
<table>
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>{
@link #EditTextExt_Oriental com.terry.attrs:Oriental}</code></td><td></td></tr>
<tr><td><code>{
@link #EditTextExt_Text com.terry.attrs:Text}</code></td><td></td></tr>
</table>
@see #EditTextExt_Oriental
@see #EditTextExt_Text
*/
public static final int [] EditTextExt = {
0x7f010000 , 0x7f010001
};
/**
<p>This symbol is the offset where the {
@link com.terry.attrs.R.attr#Oriental}
attribute's value can be found in the {
@link #EditTextExt} array.

<p>Must be one of the following constant values.</p>
<table>
<colgroup align="left" />
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Constant</th><th>Value</th><th>Description</th></tr>
<tr><td><code>Horizontal</code></td><td>1</td><td></td></tr>
<tr><td><code>Vertical</code></td><td>0</td><td></td></tr>
</table>
@attr name android:Oriental
*/
public static final int EditTextExt_Oriental = 1 ;
/**
<p>This symbol is the offset where the {
@link com.terry.attrs.R.attr#Text}
attribute's value can be found in the {
@link #EditTextExt} array.

<p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"
or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".
<p>May be a string value, using '//;' to escape characters such as '//n' or '//uxxxx' for a unicode character.
@attr name android:Text
*/
public static final int EditTextExt_Text = 0 ;
};
复制代码

好了,上述的代码写完,我们要在XML布局如何使用呢?这个会跟Android 提供的基础组件的使用方法是一致的。首先,我们要为其提供一个引用包名如下:

xmlns:android = " http://schemas.android.com/apk/res/android "
xmlns:terry
= " http://schemas.android.com/apk/res/com.terry.attrs " 复制代码

上面提供的是android 基础组件的包名,和我们自己组件的包名。

写好了包名。就可以像使用andriod 基础组件一样使用了,如下全部XML布局源码:

<? xml version="1.0" encoding="utf-8" ?>
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:terry
="http://schemas.android.com/apk/res/com.terry.attrs"
android:orientation
="vertical" android:layout_width ="fill_parent"
android:layout_height
="fill_parent" >
< TextView android:layout_width ="fill_parent"
android:layout_height
="wrap_content" android:text ="@string/hello" />

< com.terry.attrs.EditTextExt android:id ="@+id/ss"
android:layout_width
="fill_parent" android:layout_height ="wrap_content"
terry:Text
="fdsafda" terry:Oriental ="Vertical" ></ com.terry.attrs.EditTextExt >

< com.terry.attrs.EditTextExt1 android:id ="@+id/ss3"
android:layout_width
="wrap_content" android:layout_height ="wrap_content"
Text
="@string/app_name" ></ com.terry.attrs.EditTextExt1 >
</ LinearLayout >
复制代码

运行效果如下:

Android 中自定义控件和属性(attr.xml,declare-styleable,TypedArray)的方法和使用

这是这两种为Android 注册 属性的使用方法,那么两者有什么区别呢?

在这里我认为起码有五点,大家可以找找看还有什么区别:

  • 第二种可以编译时报错,如果编程人员随便输入什么第一种是不会报错的,第二种可以支持代码检测功能。
  • 第二种写法,跟Android 属性标准写法是一致的,而且可以统一书法规则。
  • 第二种写法,可以支持数据格式的验证,比如我们在attrs上注明只支持integer 那么就不可以使用字符串,这是第一种达不到的。
  • 第二种写法,可以为VIEW提供选择操作,比如如上我们使用的ENUM让VIEW对应的属性支持ENUM列表,或者为其提供BOOL等只有双项选择的操作。
  • 第一种写法,所有的属性必须是引用自资源(不大确定,如果朋友有什么好的DEMO麻烦共享),第二种写法,可以即支持引用资源又可以直接输入做操作,为编程带来更多的方便性。

种种都说明,第二种写法更具规范性,功能更性,代码编写 也更优雅,但个人有个人的使用习惯,我两种都喜欢用,具体看需求吧。呵呵。。。

更多相关文章

  1. Android的layout_weight属性释疑
  2. 通过JavaScript或PHP检测Android设备的代码
  3. Android Material Design 之CardView 属性解析及使用
  4. 图文详解Android属性动画
  5. android 软件更新代码
  6. Ubuntu 下 Android源代码下载指南
  7. Android中图像变换Matrix的原理、代码验证和应用(一)

随机推荐

  1. 查看移动App排名和推荐的网站分享
  2. Android通过onDraw实现在View中绘图操作
  3. android 布局实例解析 柱状图效果
  4. Android(安卓)扫码器串口通讯
  5. Android(安卓)CTS 测试总结
  6. OpenGL ES 学习笔记(一)
  7. Android(安卓)录音
  8. android android.bat批处理
  9. 使用adb签名并安装Android程序
  10. android wearable 研究