最简单的自定义控件,不带全名空间。直接就在某个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.youkuaiyun.com/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>