现在的位置: 首页 > 综合 > 正文

学习日志–自定义控件

2018年01月29日 ⁄ 综合 ⁄ 共 8682字 ⁄ 字号 评论关闭

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

抱歉!评论已关闭.