隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0

          導航

          <2010年4月>
          28293031123
          45678910
          11121314151617
          18192021222324
          2526272829301
          2345678

          公告

          關注我的新浪微博

          我的著作









          常用鏈接

          留言簿(126)

          我參與的團隊

          隨筆分類(818)

          隨筆檔案(310)

          文章分類(1)

          文章檔案(8)

          相冊

          ADSL、3G查詢

          CSDN

          eclipse

          ibm

          Java EE

          Linux

          Web

          云服務

          代理網站

          關注的網站

          協議

          喜歡的Blog

          國內廣告平臺

          圖書出版

          在線培訓

          開發工具

          微博客戶端

          手機鈴聲

          操作系統

          • ReactOS
          • 一個與windowXP/2003兼容的操作系統

          數學

          文件格式

          源碼資源

          移動(Mobile)

          編程語言

          英語學習

          最新隨筆

          搜索

          •  

          積分與排名

          • 積分 - 1972414
          • 排名 - 6

          最新評論

          閱讀排行榜

          評論排行榜

          新書內容連載(1):自定義Android組件之帶圖像的TextView


          本文為原創,如需轉載,請注明作者和出處,謝謝!

          本文為新書《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" />

          上面的代碼配置了一個標準的TextView組件。在這段代碼中主要有兩部分組成:組件標簽(<TextView>)和標簽屬性(android:idandroid:layout_width等)。需要注意的是,在所有的標簽屬性前面都需要加了一個命名空間(android)。實際上,android命名空間的值是在Android系統中預定義的,所有Android系統原有的組件在配置時都需要在標簽屬性前加android
              對于定制組件,可以有如下
          3種選擇。
              1.  仍然沿用android命名空間。
              2.  改用其他的命名空間。
              3.  不使用命名空間。

          雖然上面3種選擇從技術上說都沒有問題,但作者建議使用第2種方式(尤其是對外發布的組件),這是因為在使用定制組件時,可能需要指定相同名稱的屬性,在這種情況下,可以通過命名空間來區分這些屬性,例如,有兩個命名空間:androidmobile,這時可以在各自的命名空間下有相同名稱的屬性,如android:srcmobile:src。在本例中定義了一個mobile命名空間,因此,在配置本例實現的組件時需要在屬性前加mobile
              實現定制組件的一個重要環節就是讀取配置文件中相應標簽的屬性值,由于本例要實現的組件類需要從
          TextView類繼承,因此,只需要覆蓋TextView類中帶AttributeSet類型參數的構造方法即可,該構造方法的定義如下:

          public TextView(Context context, AttributeSet attrs)

          在構造方法中可以通過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 + 20);
                  }
                  
          super.onDraw(canvas);
              }
          }

          在編寫上面代碼時需要注意如下3點:
          1.  需要指定命名空間的值。該值將在<LinearLayout>標簽的xmlns:mobile屬性中定義。
          2.  如果在配置組件的屬性時指定了命名空間,需要在AttributeSet 接口的相應getter方法中的第1個參數指定命名空間的值,而第2個參數只需指定不帶命名空間的屬性名即可。
          3.  TextView類中的onDraw方法一定要在translate方法后面執行,否則系統不會移動TextView中的文本。

          下面在main.xml文件中配置了7IconTextView組件,分別設置了不同的字體大小,同時,文本前面的圖像也會隨著字體大小的變化而放大或縮小,配置代碼如下:

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




          Android開發完全講義(第2版)(本書版權已輸出到臺灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2010-04-29 09:09 銀河使者 閱讀(3199) 評論(2)  編輯  收藏 所屬分類: 原創移動(mobile)GoogleAndroid/OPhone

          評論

          # re: 新書內容連載(1):自定義Android組件之帶圖像的TextView  回復  更多評論   

          按開始的空間上空間啊
          2010-04-30 12:07 | 樂蜂網

          # re: 新書內容連載(1):自定義Android組件之帶圖像的TextView  回復  更多評論   

          樓主比較細心,注釋這么詳細。
          學習了。
          2010-05-03 00:57 | 爪天下
          主站蜘蛛池模板: 清苑县| 昆山市| 福泉市| 沙坪坝区| 丰台区| 庐江县| 威远县| 灵璧县| 河西区| 华容县| 南京市| 聂荣县| 建阳市| 石阡县| 延寿县| 郁南县| 民勤县| 岗巴县| 武定县| 彭阳县| 曲水县| 邢台市| 叶城县| 澄城县| 涟源市| 灵璧县| 丹阳市| 台北县| 吉木乃县| 土默特左旗| 佳木斯市| 漾濞| 泸溪县| 林甸县| 盐池县| 额尔古纳市| 股票| 寻乌县| 鄂温| 白山市| 岱山县|