天天看點

Android.自定義控件的實作_RadioButton 和RadioGroup

Android.自定義控件的實作

         可能是一直都在做Web的富用戶端開發的緣故吧,在接觸Android之後,發現其控件實在慘不忍睹(不知道是否說得過于偏激),我所說的慘不忍睹的意思不是說控件難看,Android的控件非常漂亮,這是我們公司公認的,但是最大的缺點在于控件功能非常弱小。弱小得一個Radio隻能放一個text,而沒有value(key)可以存放。這就是為什麼我說慘不忍睹的原因。

         但是這不能怪google,畢竟才剛剛發展起來,Android提供的隻是一個最基本的控件實作,而非一個完整、強大的實作。可幸的是,Android提供了自定義控件的實作。有了自定義控件,我們就可以再Android的基礎控件上實作我們想要的功能了。經過一天的摸索,我終于實作了我第一個自定義的組合控件——RadioButton組合RadioGroup!

         下面我将帶領大家進入Android自定義控件的世界。如果覺得我的文章能夠幫助大家的話,請大方留下你的一些話語。因為你們的留言是我分享經驗的精神源泉!謝謝!

         1、設定自定義控件: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 {

   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屬性。完了?沒有。自定義控件才剛開始了。

          2、XML中引用自定義控件

          在XML中加入自定義控件其實很簡單。隻需要在控件名字前加入包名即可。如下:

 <com.lg.base.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">

 </com.lg.base.view.RadioButton>

          同樣,紅色部分可以先不看,也不需要加入到代碼中,這個時候加入會報錯,請注意。

          3、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。這樣我們就能在自定義控件中引用他們。

           4、控件屬性與XML定義綁定。

           這下子我們又回到了自定義控件的編寫上來了。先看看我們在第一點提到的紅色字型部分。這一部分就是實作控件屬性與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();綁定結束。

              5、在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>

            <com.lg.base.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">

     </com.lg.base.view.RadioButton>

</ScrollView>

            紅色部分首先聲明命名空間。命名空間為fsms.路徑是http://schemas.android.com/apk/res/這一部分是不變的,後面接的是R的路徑:rog.kandy.R。然後在自定義控件的xml描述中就可以這樣使用fsms:value="true"。這樣就實作了自定義控件的初始化指派。

             6、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。在這裡不多說了。相信大家都能看懂。