定制控件的方式
? 继承其它控件类(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 }
时间: 2024-12-29 21:43:57