本文為原創,如需轉載,請註明作者和出處,謝謝!
本文為新書《Android/OPhone 開發完全講義》的內容連載。《Android/OPhone開發完全講義》一書現已出版,敬請關注。
購 買:互動網
《Android/OPhone 開發完全講義》目錄
原始碼下載
在本例中要實現一個可以在文本前方添加一個 映像(可以是任何Android系統支援的映像格式)的TextView組件。在編寫代碼之前,先看一下Android組件的配置代碼。
<TextView android:id="@+id/textview1" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="textview1" />
在構造方法中可以通過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);
// getAttributeResourceValue方法用來獲得組件屬性的值,在 本例中需要通過該方法的第1個參數指
// 定命名空間的值。該方法的第2個參數表示組件屬性名稱(不包括命名空間名稱),第3個 參數表示默
// 認值,也就是如果該屬性不存在,則返回第3個參數指定的值
resourceId = attrs.getAttributeResourceValue(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. 需要指定命名空間的值。該值將在<LinearLayout>標籤的xmlns:mobile屬性中定義。
2. 如果在配置組件的屬性時指定了命名空間,需要在AttributeSet 介面的相應getter方法中的第1個參數指定命名空間的值,而第2個參數只需指定不帶命名空間的屬性名稱即可。
3. TextView類中的onDraw方法一定要在translate方法後面執行,否則系統不會移動TextView中的文本。
運行本執行個體後,將顯示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>
下一篇:新書內容連載(2):Android Activity的生命週期