最简单的自定义控件,不带全名空间。直接就在某个View的构造方法里写这些个数据,构造方法的上部分其实就是读取这些个配置数据的大小,然后在最后调用某个布局,把刚刚读取到值给设置进去。
package cn.eoe.widget; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.widget.LinearLayout; import android.widget.TextView; import cn.eoe.label.edittext.R; public class LabelEditText extends LinearLayout { private TextView textView; private String labelText; private int labelFontSize; private String labelPosition; public LabelEditText(Context context, AttributeSet attrs) { super(context, attrs); // 读取labelText属性的资源ID int resourceId = attrs.getAttributeResourceValue(null, "labelText", 0); // 未获得资源ID,继续读取属性值 if (resourceId == 0) labelText = attrs.getAttributeValue(null, "labelText"); // 从资源文件中获得labelText属性的值 else labelText = getResources().getString(resourceId); // 如果按两种方式都未获得labelTex属性的值,表示未设置该属性,抛出异常 if (labelText == null) { throw new RuntimeException("必须设置labelText属性."); } // 获得labelFontSize属性的资源ID resourceId = attrs.getAttributeResourceValue(null, "labelFontSize", 0); // 继续读取labelFontSize属性的值,如果未设置该属性,将属性值设为14 if (resourceId == 0) labelFontSize = attrs.getAttributeIntValue(null, "labelFontSize", 14); // 从资源文件中获得labelFontSize属性的值 else labelFontSize = getResources().getInteger(resourceId); // 获得labelPosition属性的资源ID resourceId = attrs.getAttributeResourceValue(null, "labelPosition", 0); // 继续读取labelPosition属性的值 if (resourceId == 0) labelPosition = attrs.getAttributeValue(null, "labelPosition"); // 从资源文件中获得labelPosition属性的值 else labelPosition = getResources().getString(resourceId); // 如果未设置labelPosition属性值,将该属性值设为left if (labelPosition == null) labelPosition = "left"; String infService = Context.LAYOUT_INFLATER_SERVICE; LayoutInflater li; // 获得LAYOUT_INFLATER_SERVICE服务 li = (LayoutInflater) context.getSystemService(infService); LinearLayout linearLayout = null; // 根据labelPosition属性的值装载不同的布局文件 if("left".equals(labelPosition)) linearLayout = (LinearLayout)li.inflate(R.layout.labeledittext_horizontal, this); else if("top".equals(labelPosition)) linearLayout = (LinearLayout)li.inflate(R.layout.labeledittext_vertical, this); else throw new RuntimeException("labelPosition属性的值只能是left或top."); // 下面的代码从相应的布局文件中获得了TextView对象,并根据LabelTextView的属性值设置TextView的属性 textView = (TextView) findViewById(R.id.textview); //textView.setTextSize((float)labelFontSize); textView.setTextSize(labelFontSize); textView.setText(labelText); } }
这个是通过重写onDraw来实现的,上个是继承 了LinearLayout不用再重写ondraw方法,这个是继承 了TextView方法,重写了onDraw方法。
而且用到了命名空间。
package cn.eoe.widget; import android.R.anim; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.TextView; public class IconTextView extends TextView { // 命名空间的值 private final String namespace = "http://cn.eoe.icon.textview"; // 图像资源ID private int resourceId = 0; private Bitmap bitmap; public IconTextView(Context context, AttributeSet attrs) { super(context, attrs); resourceId = attrs.getAttributeResourceValue(namespace, "iconSrc", 0); if (resourceId > 0) bitmap = BitmapFactory.decodeResource(getResources(), resourceId); } /** * 这个效果其实也可以通过上个方法继承LinearLayout来实现,上个是用自己的ondraw因为布局本来就是写好的,所以不用重写ondraw * ,而这个其实是直接画出来的。 */ @Override protected void onDraw(Canvas canvas) { if (bitmap != null) { // 从原图上截取图像的区域,在本例中为整个图像 Rect src = new Rect(); // 将截取的图像复制到bitmap上的目标区域,在本例中与复制区域相同 Rect target = new Rect(); src.left = 0; src.top = 0; src.right = bitmap.getWidth(); src.bottom = bitmap.getHeight(); int textHeight = (int) getTextSize(); target.left = 0; // 计算图像复制到目录区域的纵坐标。由于TextView中文本内容并不是从最顶端开始绘制的,因此,需要重新计算绘制图像的纵坐标 target.top = (int) ((getMeasuredHeight() - getTextSize()) / 2) + 1; target.bottom = target.top + textHeight; // 为了保证图像不变形,需要根据图像高度重新计算图像的宽度 target.right = (int) (textHeight * (bitmap.getWidth() / (float) bitmap .getHeight())); // 开始绘制图像 canvas.drawBitmap(bitmap, src, target, getPaint()); // 将TextView中的文本向右移动一定的距离(在本例中移动了图像宽度加2个象素点的位置) canvas.translate(target.right + 2, 0); } super.onDraw(canvas); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:mobile="http://cn.eoe.icon.textview" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第一个图标" mobile:iconSrc="@drawable/android" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第二个图标" android:textSize="24dp" mobile:iconSrc="@drawable/android" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第三个图标" android:textSize="36dp" mobile:iconSrc="@drawable/android" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第四个图标" android:textSize="48dp" mobile:iconSrc="@drawable/android" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第五个图标" android:textSize="36dp" mobile:iconSrc="@drawable/android" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第六个图标" android:textSize="24dp" mobile:iconSrc="@drawable/android" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第七个图标" mobile:iconSrc="@drawable/android" /> </LinearLayout>
另外一种实现方法用TypeArray.
<resources> <attr name="iconPosition"> <enum name="left" value="0" /> <enum name="right" value="1" /> </attr> <declare-styleable name="IconTextView"> <attr name="iconSrc" format="reference" /> <attr name="iconPosition" /> </declare-styleable> </resources>
package cn.eoe.widget; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.TextView; import cn.eoe.icon.textview.ext.R; public class IconTextView extends TextView { // 图像资源ID private int resourceId = 0; // icon位置 0:left 1:right private int iconPosition = 0; private Bitmap bitmap; public IconTextView(Context context, AttributeSet attrs) { super(context, attrs); /** * http://blog.csdn.net/lilu_leo/article/details/7449973 */ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.IconTextView); resourceId = typedArray.getResourceId(R.styleable.IconTextView_iconSrc, 0); if (resourceId > 0) bitmap = BitmapFactory.decodeResource(getResources(), resourceId); iconPosition = typedArray.getInt(R.styleable.IconTextView_iconPosition, 0); } @Override protected void onDraw(Canvas canvas) { if (bitmap != null) { // 从原图上截取图像的区域,在本例中为整个图像 Rect src = new Rect(); // 将截取的图像复制到bitmap上的目标区域,在本例中与复制区域相同 Rect target = new Rect(); src.left = 0; src.top = 0; src.right = bitmap.getWidth(); src.bottom = bitmap.getHeight(); int textHeight = (int) getTextSize(); int left = 0; if (iconPosition == 1) { left = (int) getPaint().measureText(getText().toString()) + 2; } target.left = left; // 计算图像复制到目录区域的纵坐标。由于TextView中文本内容并不是从最顶端开始绘制的,因此,需要重新计算绘制图像的纵坐标 target.top = (int) ((getMeasuredHeight() - getTextSize()) / 2) + 1; target.bottom = target.top + textHeight; // 为了保证图像不变形,需要根据图像高度重新计算图像的宽度 target.right = left + (int) (textHeight * (bitmap.getWidth() / (float) bitmap .getHeight())); // 开始绘制图像 canvas.drawBitmap(bitmap, src, target, getPaint()); // 将TextView中的文本向右移动一定的距离(在本例中移动了图像宽度加2个象素点的位置) if (iconPosition == 0) canvas.translate(target.right + 2, 0); } super.onDraw(canvas); } }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/cn.eoe.icon.textview.ext" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第一个图标" app:iconSrc="@drawable/android" app:iconPosition="left" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第二个图标" android:textSize="24sp" app:iconSrc="@drawable/android" app:iconPosition="right" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第三个图标" android:textSize="36sp" app:iconSrc="@drawable/android" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第四个图标" android:textSize="48sp" app:iconSrc="@drawable/android" app:iconPosition="right" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第五个图标" android:textSize="36sp" app:iconSrc="@drawable/android" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第六个图标" android:textSize="24sp" app:iconSrc="@drawable/android" app:iconPosition="right" /> <cn.eoe.widget.IconTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="第七个图标" app:iconSrc="@drawable/android" /> </LinearLayout>