[轉]Android自定義控件的實現

本文轉自:http://kandy0619.blog.163.com/blog/static/64344345201012325939280/
多是一直都在作Web的富客戶端開發的緣故吧,在接觸Android以後,發現其控件實在慘不忍睹(不知道是否說得過於偏激),我所說的慘不忍睹的意思不是說控件難看,Android的控件很是漂亮,這是咱們公司公認的,可是最大的缺點在於控件功能很是弱小。弱小得一個Radio只能放一個text,而沒有value(key)能夠存放。這就是爲何我說慘不忍睹的緣由。
         可是這不能怪google,畢竟纔剛剛發展起來,Android提供的只是一個最基本的控件實現,而非一個完整、強大的實現。可幸的是,Android提供了自定義控件的實現。有了自定義控件,咱們就能夠再Android的基礎控件上實現咱們想要的功能了。通過一天的摸索,我終於實現了我第一個自定義的組合控件——RadioButton組合RadioGroup!
         下面我將帶領你們進入Android自定義控件的世界。若是以爲個人文章可以幫助你們的話,請大方留下你的一些話語。由於大家的留言是我分享經驗的精神源泉!謝謝!
         一、設置自定義控件:Android自帶的RadioButton只能存放text,這不符合咱們的需求,咱們須要一個能夠同時存放key-value對應的鍵值。因此咱們要編寫一個自定義控件能存放key-value。
               設計思路:新建一個類叫org.kandy.view.RadioButton,繼承自android.wedget.RadioButton,重寫父類的全部構造方法。這樣咱們就實現了一個跟父類一摸同樣的控件。在此基礎上加入咱們須要的功能:加入一個屬性value,用來存放RadioButton的key。
               代碼以下:
 
 public class RadioButton extends android.widget.RadioButton {
 private String mValue;
 public RadioButton(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
 }
 
 public String getValue() {
  return this.mValue;
 }
 public void setValue(String value) {
  this.mValue = value;
 }
 public RadioButton(Context context, AttributeSet attrs) {
  super(context, attrs);
  try {
   /**
    * 跟values/attrs.xml裏面定義的屬性綁定
    */
   TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.RadioButton);
   this.mValue = a.getString(R.styleable.RadioButton_value);
   a.recycle();
  } catch (Exception e) {
   e.printStackTrace();
  }
  
 }
 public RadioButton(Context context) {
  super(context);
 }
 
}
 
         紅色代碼能夠先不看。先看咱們新加入的屬性value,因爲Android習慣屬性命名以m開頭。因此咱們自定義控件就按照這個規則來寫。不過對於setter、getter方法來講,不須要加入m。像上面的:屬性名稱mValue,setter:setValue(),getter:getValue()。固然,你也能夠不按照Android的習慣來命名。
         這樣,咱們就可使用這個自定義控件了。並且能夠給它設置一個value,加上父類的text屬性。咱們就能夠在RadioButton中加入key-value的鍵值了。固然,這裏面的key對應是控件的value屬性,value是對應控件的text屬性。完了?沒有。自定義控件纔剛開始了。
         
          二、XML中引用自定義控件
          在XML中加入自定義控件其實很簡單。只須要在控件名字前加入包名便可。以下:
 
 <org.kandy.view.RadioButton android:id="@id/isPayDepositTrue" fsms:value="true"
      android:layout_width="wrap_content" android:layout_height="wrap_content"
      android:text="@string/yes" android:textSize="18sp">
 </org.kandy.view.RadioButton>
 
          一樣,紅色部分能夠先不看,也不須要加入到代碼中,這個時候加入會報錯,請注意。
        
          三、attrs.xml屬性定義。
          在咱們的思想中,既然我在自定義控件中加入了一個新的屬性,那麼我就應該可以在xml中引用它,並對它賦初始值。我當初也是這樣想的。但是卻無從下手。就是這一點,折騰了我一個下午。
           正解:res/values/attrs.xml中定義屬性,在自定義控件中獲取這個屬性,而後跟自定義控件的屬性相綁定。
                attrs.xml若是沒有,就新建一個。這裏只存放自定義控件中須要的屬性,在我看來,這個文件是一箇中介,負責將layout/xx.xml裏面的對這個變量的引用和自定義控件裏面的屬性綁定起來。
                 attrs.xml完整代碼以下:
 
 <?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="RadioButton"><!-- 控件名稱-->
  <attr name="value" format="string"/><!-- 屬性名稱,類型-->
 </declare-styleable>
</resources>
 
               若是res下沒有錯誤的話,在R中應該就會生成這些資源的id。這樣咱們就能在自定義控件中引用他們。
 
           四、控件屬性與XML定義綁定。
           這下子咱們又回到了自定義控件的編寫上來了。先看看咱們在第一點提到的紅色字體部分。這一部分就是實現控件屬性與XML定義綁定的代碼。
 
  /**
    * 跟values/attrs.xml裏面定義的屬性綁定
    */
   TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.RadioButton);
   this.mValue = a.getString(R.styleable.RadioButton_value);
   a.recycle();
 
 
            TypedArray其實就是一個存放資源的Array,首先從上下文中獲取到R.styleable.RadioButton這個屬性資源的資源數組。attrs是構造函數傳進來,應該就是對應attrs.xml文件。a.getString(R.styleable.RadioButton_value);這句代碼就是獲取attrs.xml中定義的屬性,並將這個屬性的值傳給本控件的mValue.最後,返回一個綁定結束的信號給資源:a.recycle();綁定結束。
 
              五、在xml中對控件賦初始值。
             請看第2點,綁定結束後能夠在須要賦初始值的地方賦值。
 
 <ScrollView android:layout_width="fill_parent"
 android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:fsms=http://schemas.android.com/apk/res/org.kandy>
            <org.kandy.view.RadioButton android:id="@id/isPayDepositTrue" fsms:value="true"
      android:layout_width="wrap_content" android:layout_height="wrap_content"
      android:text="@string/yes" android:textSize="18sp">
     </org.kandy.view.RadioButton>
</ScrollView>
 
            紅色部分首先聲明命名空間。命名空間爲fsms.路徑是http://schemas.android.com/apk/res/這一部分是不變的,後面接的是R的路徑:org.kandy.R。而後在自定義控件的xml描述中就能夠這樣使用fsms:value="true"。這樣就實現了自定義控件的初始化賦值。
 
             六、RadioGroup、RadioButton組合控件的實現
                  上面是自定義控件的實現,下面將要說的是組合控件的實現。在組合控件中,最常常用到的應該就是RadioGroup和RadioButton。RadioButton的實現已經在上面介紹了。下面要介紹RadioGroup的自定義控件和功能擴展:
                    代碼以下:
 
 public class RadioGroup extends android.widget.RadioGroup {
 private String mValue;
 
 public RadioGroup(Context context, AttributeSet attrs) {
  super(context, attrs);
 }
 public RadioGroup(Context context) {
  super(context);
 }
 // 設置子控件的值
 public void setChildValue(){
  int n = this.getChildCount();
  for(int i=0;i<n;i++){
   final RadioButton radio = (RadioButton)this.getChildAt(i);
   if(radio.getValue().equals(this.mValue)){
    radio.setChecked(true);
   }else{
    radio.setChecked(false);
   }
  }
 }
 // 獲取子類的值
 public void getChildValue(){
  int n = this.getChildCount();
  for(int i=0;i<n;i++){
   RadioButton radio = (RadioButton)this.getChildAt(i);
   if(radio.isChecked()){
    this.mValue=radio.getValue();
   }
  }
 }
 
 public void setValue(String value) {
  this.mValue = value;
  setChildValue();
 }
 
 public String getValue(){
  getChildValue();
  return this.mValue;
 }
}
 
           RadioGroup只作兩件事:獲取子控件(RadioButton)所選擇的值;設置子控件要選擇的值。
           方法很是簡單,循環或者RadioGroup的子控件,檢測哪一個控件被checked,而後getValue,將此value賦值給RadioGroup的擴展屬性value。在這裏很少說了。相信你們都能看懂。
相關文章
相關標籤/搜索