标签:
a.在values/attrs.xml文件中创建自定义的属性;
b.自定义view,在view的构造方法中获取到自定义的属性;
c.重写onDraw()方法;
d.重写onMeasure()方法。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="texttitle" format="string"/>
<attr name="textcolor" format="color"/>
<attr name="textsize" format="dimension"/>
<declare-styleable name="MyTextView">
<attr name="textsize"/>
<attr name="texttitle"/>
<attr name="textcolor"/>
</declare-styleable>
</resources>
设置了一个自定义的textview,设置了字体,颜色和大小的属性。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:keke="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.best.keke.mycustondemo.MyCustomView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello World!"
keke:textcolor="#78101ff1"
keke:textsize= "30sp"
android:layout_centerInParent="true"
keke:texttitle="你好啊啊"/>
</RelativeLayout>
注意:在此处一定要声明自己的命名空间。
xmlns:keke="http://schemas.android.com/apk/res-auto"
public class MyCustomView extends TextView {
private String texttitle;
private int textcolor;
private int textSize;
private Paint paint;
private Rect rect;
public MyCustomView(Context context) {
this(context, null);
}
public MyCustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 获取到自定义的样式的属性
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyTextView, defStyleAttr, 0);
int count = array.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = array.getIndex(i);
switch (attr) {
case R.styleable.MyTextView_textcolor:
// 设置默认的颜色为蓝色
textcolor = array.getColor(attr,Color.BLUE);
break;
case R.styleable.MyTextView_textsize:
// 设置字体的大小,默认的是16sp
textSize = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
16, getResources().getDisplayMetrics()));
break;
case R.styleable.MyTextView_texttitle:
// 设置字体的标题
texttitle = array.getString(attr);
break;
}
}
// 调用此方法,方便重复利用该view中的属性。Recycles the TypedArray, to be re-used by a later caller. After calling this function you must not ever touch the typed array again.
array.recycle();
// 获取绘制文本的宽高
paint = new Paint();
paint.setTextSize(textSize);
paint.setColor(textcolor);
// 创建一个矩形
rect = new Rect();
/**
* @param text String to measure and return its bounds 要测量的文字
* @param start Index of the first char in the string to measure 测量的起始位置
* @param end 1 past the last char in the string measure 测量的最后一个字符串的位置
* @param bounds Returns the unioned bounds of all the text. Must be rect对象
* allocated by the caller.
*/
paint.getTextBounds(texttitle, 0, texttitle.length(), rect);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.GREEN);
// 设置矩形的长宽高
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
paint.setColor(textcolor);
//drawRect(float left, float top, float right, float bottom,Paint paint)
canvas.drawText(texttitle, getWidth() / 2 - rect.width() / 2, getHeight() / 2 + rect.height() / 2, paint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void drawRect(float left, float top, float right, float bottom,Paint paint)
说明:绘制一个矩型。需要注明的是绘制矩形的参数和Java中的方法不一样。
drawRect()方法的参数图解说明如下:
当我们把android:layout_width=”100dp”,android:layout_height=”100dp”的布局改成wrap_cotent的时候,发现样子是这样的:
改成是match_parent时是这样的:
可以看出,要让自定义的view支持wrap_content属性,那么久必须要重写onMeasure()方法来制定wrap_content的大小。
这是因为view类中默认的onMeasure()方法只支持EXACTLY模式,所以控件如果在自定义的时候不重写onMeasure()方法的话,那么就使用EXACTLY模式,控件只能响应你所制定的具体宽高值或者是match_parent属性,如果要支持wrap_contaent属相,那么久必须要重写onMeasure()方法。
android给我们提供了一个MeasureSpec类,来帮我们测量view,MeasureSpec是一个32位的int值,其中高两位是测量的模式,低30位使我们测量的大小:
测量的3中模式:
EXACTLY:精确模式,当我们的控件的layout_width或者layout_height属性为具体的属性值的到时候,比如layout_width=100dp,系统使用的是EXACTLY模式。
AT_MOST:最大值模式,当我们的控件的layout_width或者layout_height属性为wrap_content的时候,此时的控件的尺寸只要不超过父控件允许的最大尺寸即可。
UNSPECIFIED:非精确模式,不指定其大小测量模式,view想多大就多大,通常在绘制自定义view的时候才会使用。
重写onMeasure()方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获取到宽高的测量模式以及测量值
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
Log.e("tag", "" + widthMode + widthSize);
int heightMtode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
Log.e("tag", "" + heightMtode + heightSize);
int width;
int height;
// 宽如果是精确测量
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize ;
} else {
paint.setTextSize(textSize);
paint.getTextBounds(texttitle, 0, texttitle.length(), rect);
int textWidth = rect.width();
int measureWidth = getPaddingLeft() + textWidth + getPaddingRight();
width = measureWidth;
}
if (heightMtode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
paint.setTextSize(textSize);
paint.getTextBounds(texttitle, 0, texttitle.length(), rect);
float textHeight = rect.height();
int measureHeight = (int) (getPaddingTop() + textHeight + getPaddingBottom());
height = measureHeight;
}
// 重新设置空间的宽高
setMeasuredDimension(width,height);
}
重写onMeasure()方法之后的效果:
在onDraw()方法中写划线和画圆点的方法。
// 获取到自定义的view宽高
final int height = getHeight();
final int width = getWidth();
// 绘制小圆点
int[] point;
for (int i = 0; i < 100; i++) {
point = getPoint(height, width);
/**
* drawCircle (float cx, float cy, float radius, Paint paint)
* float cx:圆心的x坐标。
* float cy:圆心的y坐标。
* float radius:圆的半径。
* Paint paint:绘制时所使用的画笔。
*/
canvas.drawCircle(point[0], point[1], 1, paint);
}
int [] line;
for(int i = 0; i < 100; i ++)
{
line = getLine(height, width);
/**
* startX:起始端点的X坐标。
*startY:起始端点的Y坐标。
*stopX:终止端点的X坐标。
*stopY:终止端点的Y坐标。
*paint:绘制直线所使用的画笔。
*/
canvas.drawLine(line[0], line[1], line[2], line[3], paint);
}
public int[] getLine(int height, int width)
{
int [] tempCheckNum = {0,0,0,0};
for(int i = 0; i < 4; i+=2)
{
tempCheckNum[i] = (int) (Math.random() * width);
tempCheckNum[i + 1] = (int) (Math.random() * height);
}
return tempCheckNum;
}
private int[] getPoint(int height, int width) {
int[] tempCheckNum = {0, 0, 0, 0};
tempCheckNum[0] = (int) (Math.random() * width);
tempCheckNum[1] = (int) (Math.random() * height);
return tempCheckNum;
}
样式如下:
标签:
原文地址:http://blog.csdn.net/qq_24304811/article/details/51308663