我把3用[]标出了,所以说3不一定是必须的,当然了大部分情况下还是需要重写的。
具体理解参考:http://blog.csdn.net/lmj623565791/article/details/24252901/
/**
*
*/
package com.example.customview03;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import android.R.integer;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.TextView;
/**
* @author tuke
*
*/
public class CustomView03 extends View {
String text;
int textcolor;
int textsize;
/**
*绘制时控制文本绘制的范围
*/
private Rect mBound;
private Paint mPaint;
public CustomView03(Context context) {
this(context,null);
// 代码初始化调用的构造函数
}
public CustomView03(Context context, AttributeSet attrs) {
this(context, attrs,0);
// xml文件初始化调用的构造函数
}
public CustomView03(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// xml文件初始化调用的构造函数,获得我们所定义的自定义样式属性,类型数组,把自定义属性存放到当地变量
TypedArray array=context.getTheme().obtainStyledAttributes(attrs, R.styleable.customview03_attrs, defStyleAttr, 0);
int count=array.getIndexCount();
for(int i=0;i set = new HashSet();
while (set.size() < 4){
int randomInt = random.nextInt(10);
set.add(randomInt);
}
StringBuffer sb = new StringBuffer();
for (Integer i : set){
sb.append("" + i);
}
return sb.toString();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);//xml中设置为wrap_content的话,系统测量会是满屏
/*
* 注意:
* 重写之前先了解MeasureSpec的specMode,一共三种类型:
* EXACTLY:一般是设置了布局文件设置的是明确的值或者是MATCH_PARENT
* AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
* UNSPECIFIED:表示子布局想要多大就多大,很少使用
* 因为正是不知道内容大小才去测量
* */
int width=0,height=0;
//测量宽
int specMode=MeasureSpec.getMode(widthMeasureSpec);
int specSize=MeasureSpec.getSize(widthMeasureSpec);//主要是得到View的内容的宽度
switch (specMode)
{
case MeasureSpec.EXACTLY://1073741824
width = getPaddingLeft() + getPaddingRight() + specSize;//内容的宽度+内边距=View的宽度
break;
case MeasureSpec.AT_MOST://-2147483648
width = getPaddingLeft() + getPaddingRight() + mBound.width();
break;
}
//测量高
specMode = MeasureSpec.getMode(heightMeasureSpec);
specSize = MeasureSpec.getSize(heightMeasureSpec);//主要是得到View的内容的高度
switch (specMode)
{
case MeasureSpec.EXACTLY:
height = getPaddingTop() + getPaddingBottom() + specSize;//内容的高度+内边距=View的高度
break;
case MeasureSpec.AT_MOST:
height = getPaddingTop() + getPaddingBottom() + mBound.height();
break;
}
//这个方法在OnMesure中必须被调用,来存储已经测量的宽和高
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas){
mPaint.setColor(Color.YELLOW);
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
mPaint.setColor(Color.BLACK);
for(int i=0;i<400;i++){
Random randomx=new Random();
int rx=randomx.nextInt(getWidth());
int ry=randomx.nextInt(getHeight());
canvas.drawCircle(rx, ry, 3, mPaint);
}
mPaint.setColor(textcolor);
canvas.drawText(text, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
}
}
关于自定义属性
1,先定义属性文件attrs.xml
3,在自定义View的构造函数中通过TypedArray获取自定义属性值
package com.example.customview04;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
public class CustomView04 extends View {
private Paint myPaint;
private static final String myString = "Welcome to our Zoon!";
public CustomView04(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public CustomView04(Context context, AttributeSet attr) {
super(context, attr);
myPaint = new Paint();
//获取自定义的属性
TypedArray a = context.obtainStyledAttributes(attr, R.styleable.myView);//TypedArray是一个数组容器
float textSize = a.getDimension(R.styleable.myView_textSize, 30);//防止在XML文件里没有定义,就加上了默认值30
int textColor = a.getColor(R.styleable.myView_textColor, 0xFFFFFFFF);//同上,这里的属性是:名字_属性名
myPaint.setTextSize(textSize);
myPaint.setColor(textColor);
a.recycle();//我的理解是:返回以前取回的属性,供以后使用。以前取回的可能就是textSize和textColor初始化的那段
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
//myPaint = new Paint();
myPaint.setColor(Color.RED);
myPaint.setStyle(Style.FILL);
canvas.drawRect(new Rect(10,10,100,100), myPaint);
myPaint.setColor(Color.WHITE);
canvas.drawText(myString, 10, 100, myPaint);
}
}
AttributeSet的作用就是在控件进行初始化的时候,解析布局文件中该控件的属性(keyeg:background)与该值(valueeg:@drawable/icon)的信息封装在AttributeSet中,传递给该控件(View)的构造函数。
对于非Android自带的属性,在View类中处理时是无法识别的,因此需要我们自己解析。所以这就要用到另外一个类TypedArray。在AttributeSet中我们有属性名称,有属性值,但是控件如何知道哪个属性代表什么意思呢?这个工作就由TypedArray来做了。
TypedArray对象封装了/values/attrs.xml中的styleable里定义的每个属性的类型信息,通过TypedArray我们就可以知道AttributeSet中封装的值到底是干什么的了,从而可以对这些数据进行应用。
具体理解参考http://blog.csdn.net/lmj623565791/article/details/45022631/