[转]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。在这里很少说了。相信你们都能看懂。
相关文章
相关标签/搜索