http://www.blogjava.net/nokiaguy/archive/2010/04/archive/2010/04/13/318124.html
- <TextView android:id="@+id/textview1" android:layout_width="fill_parent"
-
android:layout_height="wrap_content" android:text="textview1" - />
上面的代码配置了一个标准的TextView组件。在这段代码中主要有两部分组成:组件标签(<TextView>)和标签属性(android:id、android:layout_width等)。需要注意的是,在所有的标签属性前面都需要加了一个命名空间(android)。实际上,android命名空间的值是在Android系统中预定义的,所有Android系统原有的组件在配置时都需要在标签属性前加android。
虽然上面3种选择从技术上说都没有问题,但作者建议使用第2种方式(尤其是对外发布的组件),这是因为在使用定制组件时,可能需要指定相同名称的属性,在这种情况下,可以通过命名空间来区分这些属性,例如,有两个命名空间:android和mobile,这时可以在各自的命名空间下有相同名称的属性,如android:src和mobile:src。在本例中定义了一个mobile命名空间,因此,在配置本例实现的组件时需要在属性前加mobile。
[code=java]public TextView(Context context, AttributeSet attrs)[/code]在构造方法中可以通过AttributeSet接口的相应getter方法来读取指定的属性值,如果在配置属性时指定了命名空间,需要在使用getter方法获得属性值时指定这个命名空间,如果未指定命名空间,则将命名空间设为null即可。
IconTextView是本例要编写的组件类,该类从TextView继承,在onDraw方法中将TextView中的文本后移,并在文本的前方添加了一个图像,该图像的资源ID通过mobile:iconSrc属性来指定。IconTextView类的代码如下:
- package net.blogjava.mobile.widget;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Canvas;
- import android.graphics.Rect;
- import android.util.AttributeSet;
- import android.widget.TextView;
- public
- class IconTextView extends TextView
- {
-
// 命 - 名
- 空间的值
-
private final String namespace = "http://net.blogjava.mobile";
-
// 保 - 存
- 图像资源ID的变量
-
private int resourceId =0; -
private Bitmap bitmap; -
public IconTextView(Context context, AttributeSet attrs) -
{ -
super(context, attrs); -
// getAttributeResourceValu e 方 - 法
- 用来获得组件属性的值,在本例中需要通过该方法的第1个参数指
-
// 定命名空间的值。该方法的第2个参数表示组件属性名
- (不
- 包括命名空间名称),第3个参数表示默
-
// 认值,也就是如果该属性不存在,则返回第3个参数指定的值
-
resourceId = attrs.getAttributeResourceValu e(namespace, "iconSrc", 0); -
if (resourceId > 0) -
// 如
- 果
- 成功获得图像资源的ID,装载这个图像资源,并创建Bitmap对象
-
bitmap = BitmapFactory.decodeResource(getResources(), resourceId); -
} - @Override
- protected void onDraw(Canvas canvas)
- {
-
if (bitmap != null) -
{ -
// 从 - 原
- 图上截取图像的区域,在本例中为整个图像
-
Rect src = new Rect(); -
// 将 - 截
- 取的图像复制到bitmap上的目标区域,在本例中与复制区域相同
-
Rect target = new Rect(); -
src.left = 0; -
src.top = 0; -
src.right = bitmap.getWidth(); -
src.bottom = bitmap.getHeight(); -
int textHeight = (int) getTextSize(); -
target.left = 0; -
// 计 - 算
- 图像复制到目标区域的纵坐标。由于 TextView组件的文本内容并不是
-
// 从最顶端开始绘制的,因此,需
- 要
- 重新计算绘制图像的纵坐标
-
target.top = (int) ((getMeasuredHeight() - getTextSize()) / 2) + 1; -
target.bottom = target.top + textHeight; -
// 为 - 了
- 保证图像不变形,需要根据图像高度重新计算图像的宽度
-
target.right = (int) (textHeight * (bitmap.getWidth() / (float) bitmap.getHeight())); -
// 开 - 始
- 绘制图像
-
canvas.drawBitmap(bitmap, src, target, getPaint()); -
// 将 - TextView
- 中的文本向右移动一定的距离(在本例中移动了图像宽度加2个象素点的位置)
-
canvas.translate(target.right + 2, 0); -
} -
super.onDraw(canvas);
-
} - }
在编写上面代码时需要注意如下3点:
1.
2.
3.
下面在main.xml文件中配置了7个IconTextView组件,分别设置了不同的字体大小,同时,文本前面的图像也会随着字体大小的变化而放大或缩小,配置代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <!--
在 - 下
- 面的标签中通过xmlns:mobile属性定义了一个命名空间
-->
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-
xmlns:mobile="http://net.blogjava.mobile" android:orientation="vertical" -
android:layout_width="fill_parent" android:layout_height="fill_parent"> - <!--
mobile:iconSrc
- 是
- 可选属性,如果未设置该属性,则IconTextView与TextView的效果相同
-->
- <!-- 由于
- IconTextView
- 和Main类不在同一个包中,因此,需要显式指定package -->
- <net.blogjava.mobile.view.IconTextView
-
android:layout_width="fill_parent" android:layout_height="wrap_content" -
android:text=" 第 - 一
- 个笑脸" mobile:iconSrc="@drawable/small"
- />
- <net.blogjava.mobile.widget.IconTextView
-
android:layout_width="fill_parent" android:layout_height="wrap_content" -
android:text=" 第 - 二
- 个笑脸" android:textSize="24dp" mobile:iconSrc="@drawable/small"
- />
- <net.blogjava.mobile.widget.IconTextView
-
android:layout_width="fill_parent" android:layout_height="wrap_content" -
android:text=" 第 - 三
- 个笑脸" android:textSize="36dp" mobile:iconSrc="@drawable/small"
- />
- <net.blogjava.mobile.widget.IconTextView
-
android:layout_width="fill_parent" android:layout_height="wrap_content" -
android:text=" 第 - 四
- 个笑脸" android:textSize="48dp" mobile:iconSrc="@drawable/small"
- />
- <net.blogjava.mobile.widget.IconTextView
-
android:layout_width="fill_parent" android:layout_height="wrap_content" -
android:text=" 第 - 五
- 个笑脸" android:textSize="36dp" mobile:iconSrc="@drawable/small"
- />
- <net.blogjava.mobile.widget.IconTextView
-
android:layout_width="fill_parent" android:layout_height="wrap_content" -
android:text=" 第 - 六
- 个笑脸" android:textSize="24dp" mobile:iconSrc="@drawable/small"
- />
- <net.blogjava.mobile.widget.IconTextView
-
android:layout_width="fill_parent" android:layout_height="wrap_content" -
android:text=" 第 - 七
- 个笑脸" mobile:iconSrc="@drawable/small"
- />
- </LinearLayout>
运行本实例后,将显示如图1所示的效果。
注意:虽然很多人认为组件的属性必须以android命名空间开头,该命名空间的值必须是http://schemas.android.com/apk/res/android。实际上,只是命名空间的值必须是http://schemas.android.com/apk/res/android而已,命名空间的名称可以是任何值,如下面的代码所示:
- <?xml version="1.0" encoding="utf-8"?>
- <!--
将 - android
- 换成了abcd
--> - <LinearLayout xmlns:abcd="http://schemas.android.com/apk/res/android"
-
abcd:orientation="vertical" abcd:layout_width="fill_parent" -
abcd:layout_height="fill_parent"> - </LinearLayout>