首页 > 代码库 > 3、用继承和组合方式定制控件

3、用继承和组合方式定制控件

定制控件的方式

 

? 继承其它控件类(EditText、Button)
? 组合方式。当前控件类从容器类继承,并将若干个控件添加到当前的容器中。

? 绘制控件,也就是控件类从View继承,并在onDraw方法中从零绘制控件。例如,TextView。 

 

带标签的文本编辑框(不带命名空间)

 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" 4     android:layout_height="fill_parent" 5     android:orientation="vertical" > 6  7     <cn.eoe.widget.LabelEditText 8         android:layout_width="fill_parent" 9         android:layout_height="wrap_content"10         labelFontSize="16"11         labelPosition="left"12         labelText="姓名:" />13 14     <cn.eoe.widget.LabelEditText15         android:layout_width="fill_parent"16         android:layout_height="wrap_content"17         android:layout_marginTop="20dp"18         labelFontSize="26"19         labelPosition="top"20         labelText="兴趣爱好" />21 22 </LinearLayout>
 1 package cn.eoe.widget; 2  3 import android.content.Context; 4 import android.util.AttributeSet; 5 import android.view.LayoutInflater; 6 import android.widget.LinearLayout; 7 import android.widget.TextView; 8 import cn.eoe.label.edittext.R; 9 10 public class LabelEditText extends LinearLayout {11     private TextView textView;12     private String labelText;13     private int labelFontSize;14     private String labelPosition;15 16     public LabelEditText(Context context, AttributeSet attrs) {17         super(context, attrs);18         // 读取labelText属性的资源ID19         int resourceId = attrs.getAttributeResourceValue(null, "labelText", 0);20         // 未获得资源ID,继续读取属性值21         if (resourceId == 0)22             labelText = attrs.getAttributeValue(null, "labelText");23         // 从资源文件中获得labelText属性的值24         else25             labelText = getResources().getString(resourceId);26         // 如果按两种方式都未获得labelTex属性的值,表示未设置该属性,抛出异常27         if (labelText == null) {28             throw new RuntimeException("必须设置labelText属性.");29         }30         // 获得labelFontSize属性的资源ID31         resourceId = attrs.getAttributeResourceValue(null, "labelFontSize", 0);32         // 继续读取labelFontSize属性的值,如果未设置该属性,将属性值设为1433         if (resourceId == 0)34             labelFontSize = attrs.getAttributeIntValue(null, "labelFontSize",35                     14);36         // 从资源文件中获得labelFontSize属性的值37         else38             labelFontSize = getResources().getInteger(resourceId);39         // 获得labelPosition属性的资源ID40         resourceId = attrs.getAttributeResourceValue(null, "labelPosition", 0);41         // 继续读取labelPosition属性的值42         if (resourceId == 0)43             labelPosition = attrs.getAttributeValue(null, "labelPosition");44         // 从资源文件中获得labelPosition属性的值45         else46             labelPosition = getResources().getString(resourceId);47         // 如果未设置labelPosition属性值,将该属性值设为left48         if (labelPosition == null)49             labelPosition = "left";50 51         String infService = Context.LAYOUT_INFLATER_SERVICE;52         LayoutInflater li;53         // 获得LAYOUT_INFLATER_SERVICE服务54         li = (LayoutInflater) context.getSystemService(infService);55         LinearLayout linearLayout = null;56         // 根据labelPosition属性的值装载不同的布局文件57         if ("left".equals(labelPosition))58             linearLayout = (LinearLayout) li.inflate(59                     R.layout.labeledittext_horizontal, this);60         else if ("top".equals(labelPosition))61             linearLayout = (LinearLayout) li.inflate(62                     R.layout.labeledittext_vertical, this);63         else64             throw new RuntimeException("labelPosition属性的值只能是left或top.");65 66         // 下面的代码从相应的布局文件中获得了TextView对象,并根据LabelTextView的属性值设置TextView的属性67         textView = (TextView) findViewById(R.id.textview);68         // textView.setTextSize((float)labelFontSize);69         textView.setTextSize(labelFontSize);70         textView.setText(labelText);71 72     }73 74 }

 

带图标的文本框(带命名空间)

 

 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3     xmlns:mobile="http://cn.eoe.icon.textview" android:orientation="vertical" 4     android:layout_width="fill_parent" android:layout_height="fill_parent"> 5     <cn.eoe.widget.IconTextView 6         android:layout_width="fill_parent" android:layout_height="wrap_content" 7         android:text="第一个图标" mobile:iconSrc="@drawable/android" /> 8     <cn.eoe.widget.IconTextView 9         android:layout_width="fill_parent" android:layout_height="wrap_content"10         android:text="第二个图标" android:textSize="24dp" mobile:iconSrc="@drawable/android" />11     <cn.eoe.widget.IconTextView12         android:layout_width="fill_parent" android:layout_height="wrap_content"13         android:text="第三个图标" android:textSize="36dp" mobile:iconSrc="@drawable/android" />14     <cn.eoe.widget.IconTextView15         android:layout_width="fill_parent" android:layout_height="wrap_content"16         android:text="第四个图标" android:textSize="48dp" mobile:iconSrc="@drawable/android" />17     <cn.eoe.widget.IconTextView18         android:layout_width="fill_parent" android:layout_height="wrap_content"19         android:text="第五个图标" android:textSize="36dp" mobile:iconSrc="@drawable/android" />20     <cn.eoe.widget.IconTextView21         android:layout_width="fill_parent" android:layout_height="wrap_content"22         android:text="第六个图标" android:textSize="24dp" mobile:iconSrc="@drawable/android" />23     <cn.eoe.widget.IconTextView24         android:layout_width="fill_parent" android:layout_height="wrap_content"25         android:text="第七个图标" mobile:iconSrc="@drawable/android" />26    27 </LinearLayout>  28                
 1 package cn.eoe.widget; 2  3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.Canvas; 7 import android.graphics.Rect; 8 import android.util.AttributeSet; 9 import android.widget.TextView;10 11 public class IconTextView extends TextView {12     // 命名空间的值13     private final String namespace = "http://cn.eoe.icon.textview";14     // 图像资源ID15     private int resourceId = 0;16     private Bitmap bitmap;17 18     public IconTextView(Context context, AttributeSet attrs) {19         super(context, attrs);20 21         resourceId = attrs.getAttributeResourceValue(namespace, "iconSrc", 0);22         if (resourceId > 0)23             bitmap = BitmapFactory.decodeResource(getResources(), resourceId);24     }25 26     @Override27     protected void onDraw(Canvas canvas) {28         if (bitmap != null) {29 30             // 从原图上截取图像的区域,在本例中为整个图像31             Rect src = http://www.mamicode.com/new Rect();32             // 将截取的图像复制到bitmap上的目标区域,在本例中与复制区域相同33             Rect target = new Rect();34             src.left = 0;35             src.top = 0;36             src.right = bitmap.getWidth();37             src.bottom = bitmap.getHeight();38 39             int textHeight = (int) getTextSize();40             target.left = 0;41             // 计算图像复制到目录区域的纵坐标。由于TextView中文本内容并不是从最顶端开始绘制的,因此,需要重新计算绘制图像的纵坐标42             target.top = (int) ((getMeasuredHeight() - getTextSize()) / 2) + 1;43             target.bottom = target.top + textHeight;44             // 为了保证图像不变形,需要根据图像高度重新计算图像的宽度45             target.right = (int) (textHeight * (bitmap.getWidth() / (float) bitmap46                     .getHeight()));47             // 开始绘制图像48             canvas.drawBitmap(bitmap, src, target, getPaint());49             // 将TextView中的文本向右移动一定的距离(在本例中移动了图像宽度加2个象素点的位置)50 51             canvas.translate(target.right + 2, 0);52         }53         super.onDraw(canvas);54 55     }56 57 }

 

控件属性验证 

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2     xmlns:app="http://schemas.android.com/apk/res/cn.eoe.icon.textview.ext" 3     android:orientation="vertical" android:layout_width="fill_parent" 4     android:layout_height="fill_parent"> 5     <cn.eoe.widget.IconTextView 6         android:layout_width="fill_parent" android:layout_height="wrap_content" 7         android:text="第一个图标" app:iconSrc="@drawable/android" app:iconPosition="left" /> 8     <cn.eoe.widget.IconTextView 9         android:layout_width="fill_parent" android:layout_height="wrap_content"10         android:text="第二个图标" android:textSize="24sp" app:iconSrc="@drawable/android"11         app:iconPosition="right" />12     <cn.eoe.widget.IconTextView13         android:layout_width="fill_parent" android:layout_height="wrap_content"14         android:text="第三个图标" android:textSize="36sp" app:iconSrc="@drawable/android" />15     <cn.eoe.widget.IconTextView16         android:layout_width="fill_parent" android:layout_height="wrap_content"17         android:text="第四个图标" android:textSize="48sp" app:iconSrc="@drawable/android"18         app:iconPosition="right" />19     <cn.eoe.widget.IconTextView20         android:layout_width="fill_parent" android:layout_height="wrap_content"21         android:text="第五个图标" android:textSize="36sp" app:iconSrc="@drawable/android" />22     <cn.eoe.widget.IconTextView23         android:layout_width="fill_parent" android:layout_height="wrap_content"24         android:text="第六个图标" android:textSize="24sp" app:iconSrc="@drawable/android"25         app:iconPosition="right" />26     <cn.eoe.widget.IconTextView27         android:layout_width="fill_parent" android:layout_height="wrap_content"28         android:text="第七个图标" app:iconSrc="@drawable/android" />29 30 </LinearLayout>  31                
 1 package cn.eoe.widget; 2  3 import android.content.Context; 4 import android.content.res.TypedArray; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapFactory; 7 import android.graphics.Canvas; 8 import android.graphics.Rect; 9 import android.util.AttributeSet;10 import android.widget.TextView;11 import cn.eoe.icon.textview.ext.R;12 13 public class IconTextView extends TextView {14     // 图像资源ID15     private int resourceId = 0;16     // icon位置 0:left 1:right17     private int iconPosition = 0;18     private Bitmap bitmap;19 20     public IconTextView(Context context, AttributeSet attrs) {21         super(context, attrs);22 23         TypedArray typedArray = context.obtainStyledAttributes(attrs,24                 R.styleable.IconTextView);25 26         resourceId = typedArray.getResourceId(R.styleable.IconTextView_iconSrc,27                 0);28         if (resourceId > 0)29             bitmap = BitmapFactory.decodeResource(getResources(), resourceId);30         iconPosition = typedArray.getInt(R.styleable.IconTextView_iconPosition,31                 0);32     }33 34     @Override35     protected void onDraw(Canvas canvas) {36         if (bitmap != null) {37 38             // 从原图上截取图像的区域,在本例中为整个图像39             Rect src = http://www.mamicode.com/new Rect();40             // 将截取的图像复制到bitmap上的目标区域,在本例中与复制区域相同41             Rect target = new Rect();42             src.left = 0;43             src.top = 0;44             src.right = bitmap.getWidth();45             src.bottom = bitmap.getHeight();46 47             int textHeight = (int) getTextSize();48             int left = 0;49             if (iconPosition == 1) {50                 left = (int) getPaint().measureText(getText().toString()) + 2;51             }52             target.left = left;53             // 计算图像复制到目录区域的纵坐标。由于TextView中文本内容并不是从最顶端开始绘制的,因此,需要重新计算绘制图像的纵坐标54             target.top = (int) ((getMeasuredHeight() - getTextSize()) / 2) + 1;55             target.bottom = target.top + textHeight;56             // 为了保证图像不变形,需要根据图像高度重新计算图像的宽度57             target.right = left58                     + (int) (textHeight * (bitmap.getWidth() / (float) bitmap59                             .getHeight()));60             // 开始绘制图像61             canvas.drawBitmap(bitmap, src, target, getPaint());62             // 将TextView中的文本向右移动一定的距离(在本例中移动了图像宽度加2个象素点的位置)63             if (iconPosition == 0)64                 canvas.translate(target.right + 2, 0);65         }66         super.onDraw(canvas);67 68     }69 70 }

 

3、用继承和组合方式定制控件