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.LabelEditText
15         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属性的资源ID
19         int resourceId = attrs.getAttributeResourceValue(null, "labelText", 0);
20         // 未获得资源ID,继续读取属性值
21         if (resourceId == 0)
22             labelText = attrs.getAttributeValue(null, "labelText");
23         // 从资源文件中获得labelText属性的值
24         else
25             labelText = getResources().getString(resourceId);
26         // 如果按两种方式都未获得labelTex属性的值,表示未设置该属性,抛出异常
27         if (labelText == null) {
28             throw new RuntimeException("必须设置labelText属性.");
29         }
30         // 获得labelFontSize属性的资源ID
31         resourceId = attrs.getAttributeResourceValue(null, "labelFontSize", 0);
32         // 继续读取labelFontSize属性的值,如果未设置该属性,将属性值设为14
33         if (resourceId == 0)
34             labelFontSize = attrs.getAttributeIntValue(null, "labelFontSize",
35                     14);
36         // 从资源文件中获得labelFontSize属性的值
37         else
38             labelFontSize = getResources().getInteger(resourceId);
39         // 获得labelPosition属性的资源ID
40         resourceId = attrs.getAttributeResourceValue(null, "labelPosition", 0);
41         // 继续读取labelPosition属性的值
42         if (resourceId == 0)
43             labelPosition = attrs.getAttributeValue(null, "labelPosition");
44         // 从资源文件中获得labelPosition属性的值
45         else
46             labelPosition = getResources().getString(resourceId);
47         // 如果未设置labelPosition属性值,将该属性值设为left
48         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         else
64             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.IconTextView
12         android:layout_width="fill_parent" android:layout_height="wrap_content"
13         android:text="第三个图标" android:textSize="36dp" mobile:iconSrc="@drawable/android" />
14     <cn.eoe.widget.IconTextView
15         android:layout_width="fill_parent" android:layout_height="wrap_content"
16         android:text="第四个图标" android:textSize="48dp" mobile:iconSrc="@drawable/android" />
17     <cn.eoe.widget.IconTextView
18         android:layout_width="fill_parent" android:layout_height="wrap_content"
19         android:text="第五个图标" android:textSize="36dp" mobile:iconSrc="@drawable/android" />
20     <cn.eoe.widget.IconTextView
21         android:layout_width="fill_parent" android:layout_height="wrap_content"
22         android:text="第六个图标" android:textSize="24dp" mobile:iconSrc="@drawable/android" />
23     <cn.eoe.widget.IconTextView
24         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     // 图像资源ID
15     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     @Override
27     protected void onDraw(Canvas canvas) {
28         if (bitmap != null) {
29 
30             // 从原图上截取图像的区域,在本例中为整个图像
31             Rect src = 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) bitmap
46                     .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.IconTextView
13         android:layout_width="fill_parent" android:layout_height="wrap_content"
14         android:text="第三个图标" android:textSize="36sp" app:iconSrc="@drawable/android" />
15     <cn.eoe.widget.IconTextView
16         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.IconTextView
20         android:layout_width="fill_parent" android:layout_height="wrap_content"
21         android:text="第五个图标" android:textSize="36sp" app:iconSrc="@drawable/android" />
22     <cn.eoe.widget.IconTextView
23         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.IconTextView
27         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     // 图像资源ID
15     private int resourceId = 0;
16     // icon位置 0:left 1:right
17     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     @Override
35     protected void onDraw(Canvas canvas) {
36         if (bitmap != null) {
37 
38             // 从原图上截取图像的区域,在本例中为整个图像
39             Rect src = 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 = left
58                     + (int) (textHeight * (bitmap.getWidth() / (float) bitmap
59                             .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 }
原文地址:https://www.cnblogs.com/androidsj/p/3871385.html