Android自定义组合控件

 

目标:实现textview和ImageButton组合,可以通过Xml设置自定义控件的属性。
  1.控件布局:以Linearlayout为根布局,一个TextView,一个ImageButton。
  
Xml代码   收藏代码
1  <  ?xml  version ="1.0"  encoding ="utf-8" ? >  
2     <  LinearLayout  xmlns:Android ="http://schemas.android.com/apk/res/android"   
3     android:layout_width ="fill_parent"  android:layout_height ="fill_parent"   
4     android:gravity ="center_vertical" >  
5     <  TextView  android:layout_height ="wrap_content"  android:id ="@+id/text1"   
6     android:layout_width ="wrap_content" ><  /TextView >  
7     <  ImageButton  android:layout_width ="wrap_content"   
8     android:layout_height ="wrap_content"  android:id ="@+id/btn1" ><  /ImageButton >  
9     <  /LinearLayout > 

  2.自定义控件代码,从LinearLayout继承:
  
Java代码   收藏代码
     public  class ImageBtnWithText  extends LinearLayout {  
     }  
       public ImageBtnWithText(Context context) {  
       this(context,  null);  
      }  
       
       public ImageBtnWithText(Context context, AttributeSet attrs) {  
       super(context, attrs);  
      LayoutInflater.from(context).inflate(R.layout.imagebtn_with_text,  thistrue);  
        }  
      } 

  在构造函数中将Xml中定义的布局解析出来。
  3.在主界面布局xml中使用自定义控件:
  
Xml代码   收藏代码
<  com.demo.widget2.ImageBtnWithText  
   
android:id ="@+id/widget"   
   android:layout_width
="fill_parent"   
   android:layout_height
="fill_parent"   />    

  即使用完整的自定义控件类路径:com.demo.widget2.ImageBtnWithText定义一个元素。
  运行可以看到控件已经能够被加载到界面上。
  4.给按钮设置图片和文本
  如果图片是固定不变的,那么直接在控件布局中设置ImageButton的src属性即可。
  4.1通过Java代码设置,在控件代码中提供函数接口:
  
Java代码   收藏代码
public  void setButtonImageResource( int resId) {  
   mBtn.setImageResource(resId);  
   }  
    
    public  void setTextViewText(String text) {  
   mTv.setText(text);  
   }  
  

  然后再在主界面的onCreate()通过函数调用设置即可。
  4.2通过Xml设置属性
  4.2.1首先定义Xml可以设置的属性集合,在values下创建attrs.xml,文件名可随意,一般都叫attrs.xml
  
Xml代码   收藏代码
<  ?xml  version ="1.0"  encoding ="utf-8" ? >  
   <  resources >  
    <  declare-styleable  name ="ImageBtnWithText" >  
    <  attr  name ="android:text" />  
    <  attr  name ="android:src" />  
    <  /declare-styleable >  
    <  /resources >   

  属性集合名字:ImageBtnWithText,自己可根据实际来定义;
  集合中包含的属性列表,每行一个属性。
  4.2.2修改自定义控件实现代码,以获取xml中定义的属性
  
Java代码   收藏代码
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ImageBtnWithText);  
  CharSequence text = a.getText(R.styleable.ImageBtnWithText_android_text);  
   if(text !=  null) mTv.setText(text);  
  Drawable drawable = a.getDrawable(R.styleable.ImageBtnWithText_android_src);  
   if(drawable !=  null) mBtn.setImageDrawable(drawable);  
  a.recycle();

  首先通过context.obtainStyledAttributes获得所有属性数组;
  然后通过TypedArray类的getXXXX()系列接口获得相应的值。
  4.2.3在主界面布局中设置自定义控件的属
  android:text="ABC" android:src="@drawable/icon
  4.3自定义名称属性:
  在4.2中使用的属性名是Android系统命名空间的,都以android开头,比如android:text等。
实际开发中会自定义一些属性名,这些属性名仍然定义在4.2.1提到的attrs.xml中:
  4.3.1定义属性名
  
Xml代码   收藏代码
  1. <  attr  name ="appendText"  format ="string" />
     

  和直接使用系统的attr不同的是要增加一个format属性,说明此属性是什么格式的。format可选项可参见注1
  4.3.2使用自定义属性
  
Xml代码   收藏代码
<  ?xml  version ="1.0"  encoding ="utf-8" ? >  
    <  LinearLayout  xmlns:android ="http://schemas.android.com/apk/res/android"   
   xmlns:myspace
="http://schemas.android.com/apk/res/com.demo.customwidget"   
   android:orientation
="vertical"  android:layout_width ="fill_parent"   
   android:layout_height
="fill_parent" >  
    <  com.demo.widget2.ImageBtnWithText  
   
android:text ="ABC"  android:src ="@drawable/icon"  android:id ="@+id/widget"   
   android:layout_width
="fill_parent"  android:layout_gravity ="center"   
   android:layout_height
="fill_parent"  myspace:appendText ="123456" >  
    <  /com.demo.widget2.ImageBtnWithText >  
    <  /LinearLayout > 
  1.     

  直接在主布局文件中使用此属性appendText="abc"是不会设置生效的,而是要在主布局xml中定义一个xml命名空间:
xmlns:myspace="http://schemas.android.com/apk/res/com.demo.customwidget"
  命名空间的名字可以自己随便定义,此处为myspace,即xmlns:myspace;
  后面的地址则有限制,其开始必须为:"http://schemas.android.com/apk/res/",后面则是包名com.demo.customwidget,
  此处的包名与AndroidManifest.xml中< manifest>节点的属性package="com.demo.customwidget"一致,不是自定义控件Java代码所在的包,当然简单的程序自定义控件Java代码也一般在此包内。
   注1:format可选项
  "reference" //引用
  "color" //颜色
  "boolean" //布尔值
  "dimension" //尺寸值
  "float" //浮点值
  "integer" //整型值
  "string" //字符串
  "fraction" //百分数,比如200%
  枚举值,格式如下:
  < attr name="orientation">
  < enum name="horizontal" value="0" />
  < enum name="vertical" value="1" />
  < /attr>
  xml中使用时:
  android:orientation = "vertical"
  标志位,位或运算,格式如下:
  < attr name="windowSoftInputMode">
  < flag name = "stateUnspecified" value = "0" />
  < flag name = "stateUnchanged" value = "1" />
  < flag name = "stateHidden" value = "2" />
  < flag name = "stateAlwaysHidden" value = "3" />
  < flag name = "stateVisible" value = "4" />
  < flag name = "stateAlwaysVisible" value = "5" />
  < flag name = "adjustUnspecified" value = "0x00" />
  < flag name = "adjustResize" value = "0x10" />
  < flag name = "adjustPan" value = "0x20" />
  < flag name = "adjustNothing" value = "0x30" />
  < /attr>
  xml中使用时:
  android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden">
  另外属性定义时可以指定多种类型值,比如:
  < attr name = "background" format = "reference|color" />
  xml中使用时:
  android:background = "@drawable/图片ID|#00FF00"


最后来个完整实例:
Java代码   收藏代码
     import android.content.Context;  
     import android.content.res.TypedArray;  
     import android.util.AttributeSet;  
     import android.view.LayoutInflater;  
     import android.view.View;  
     import android.widget.ImageButton;  
     import android.widget.LinearLayout;  
     import android.widget.ProgressBar;  
      
     public  class Meter  extends LinearLayout {  
         private  int max=100;  
         private  int incrAmount=1;  
         private  int decrAmount=-1;  
         private ProgressBar bar= null;  
         public Meter( final Context ctxt, AttributeSet attrs) {  
             super(ctxt, attrs);  
              
             this.setOrientation(HORIZONTAL);  
              
            TypedArray a=ctxt.obtainStyledAttributes(attrs,R.styleable.Meter);  
              
             // 获取里面属性用 "名字_ 属性" 连接起来  
            max=a.getInt(R.styleable.Meter_max, 100);  
            incrAmount=a.getInt(R.styleable.Meter_incr, 1);  
            decrAmount=-1*a.getInt(R.styleable.Meter_decr, 1);  
              
            a.recycle();  
        }  
         // 当View中所有的子控件 均被映射成xml后触发  
        @Override  
         protected  void onFinishInflate() {  
             super.onFinishInflate();  
              
     //       ((Activity)getContext()).getLayoutInflater().inflate(R.layout.meter, this);  
              
            LayoutInflater.from(getContext()).inflate(R.layout.meter,  this);  
              
            bar=(ProgressBar)findViewById(R.id.bar);  
            bar.setMax(max);  
              
            ImageButton btn=(ImageButton)findViewById(R.id.incr);  
            btn.setOnClickListener( new View.OnClickListener() {  
                 public  void onClick(View v) {  
                    bar.incrementProgressBy(incrAmount);  
                }  
            });  
              
            btn=(ImageButton)findViewById(R.id.decr);  
            btn.setOnClickListener( new View.OnClickListener() {  
                 public  void onClick(View v) {  
                    bar.incrementProgressBy(decrAmount);  
                }  
            });  
     //       this.addView(view); // 不需要add,默认已经add了  
        }  
    } 

attrs.xml:
Xml代码   收藏代码
     <? xml version="1.0" encoding="utf-8" ?>  
     < resources >  
         < declare-styleable  name ="Meter" >  
             < attr  name ="max"  format ="integer"   />  
             < attr  name ="incr"  format ="integer"   />  
             < attr  name ="decr"  format ="integer"   />  
         </ declare-styleable >  
     </ resources > 

meter.xml文件:
Xml代码   收藏代码
     <? xml version="1.0" encoding="utf-8" ?>  
     < LinearLayout  xmlns:android ="http://schemas.android.com/apk/res/android"   
        android:orientation
="horizontal"   
        android:layout_width
="fill_parent"   
        android:layout_height
="wrap_content"   
    
>  
         < ImageButton  android:id ="@+id/decr"   
            android:layout_height
="wrap_content"   
            android:layout_width
="wrap_content"   
            android:scaleType
="fitCenter"   
            android:src
="@drawable/arrow_down"   
        
/>  
         < ProgressBar  android:id ="@+id/bar"   
            style
="?android:attr/progressBarStyleHorizontal"   
            android:layout_width
="wrap_content"   
            android:layout_height
="wrap_content"   
            android:layout_weight
="1"   
            android:layout_gravity
="center_vertical"   
        
/>  
         < ImageButton  android:id ="@+id/incr"   
            android:layout_height
="wrap_content"   
            android:layout_width
="wrap_content"   
            android:scaleType
="fitCenter"   
            android:src
="@drawable/arrow_up"   
        
/>  
     </ LinearLayout > 

使用:
Java代码   收藏代码
    @Override  
         public  void onCreate(Bundle savedInstanceState) {  
             super.onCreate(savedInstanceState);  
            setContentView(R.layout.main);  
        } 

main.xml:
Xml代码   收藏代码
     <? xml version="1.0" encoding="utf-8" ?>  
     < LinearLayout  xmlns:android ="http://schemas.android.com/apk/res/android"   
        xmlns:app
="http://schemas.android.com/apk/res/com.ql.app"   
        android:orientation
="horizontal"   
        android:layout_width
="fill_parent"   
        android:layout_height
="wrap_content"   
        
>  
         < com.ql.app.Meter  
            
android:id ="@+id/meter"   
            android:layout_width
="fill_parent"   
            android:layout_height
="wrap_content"   
            app:max
="100"   
            app:incr
="5"   
            app:decr
="5"   
        
/>  
     </ LinearLayout > 


 

 

 

Trackback:http://gundumw100.iteye.com/blog/1040917

你可能感兴趣的:(android)