今天我们要实现的是,自定义一个控件,控件会随机展示4个数字,和两条横线,点击会展示新的4个数据和两条横线。
如图,第一张图式开始展示的样子,第二张图是点击后展示的样子!功能很简单,但这只是刚刚起步!
现在和大家讲讲具体的实现步骤!
1,在res/values/目录下面创建一个attrs.xml文件来声明自定义的属性!
2,声明一个类继承View
3,重写构造方法,在构造方法中拿到自定义的属性
4,重写onMeasure()方法,调整布局
5,重写onDraw();方法,绘制控件
6,在布局空应用自定控件
首先我们看到第一步,我们声明了自定义属性:控件文本显示内容,文本的大小,文本的颜色!
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="titleTextSize" format="dimension"></attr>
<attr name="titleText" format="string"></attr>
<attr name="titleTextColor" format="color"></attr>
<declare-styleable name="CustomView">
<attr name="titleTextSize"/>
<attr name="titleText"/>
<attr name="titleTextColor"/>
</declare-styleable>
</resources>
2,3我们重写了构造方法,注意一个参数的构造方法,和两个参数的构造方法我们都让其调用三个参数的构造方法,这样三个参数的构造方法是必须执行的,这样我们就在
三个参数的构造方法中,拿到我们自定义的属性值。
public class CustomView extends View{
//文本显示内容
private String titleText;
//字体颜色
private int titleTextColor;
//字体大小
private int titleTextSize;
//画笔对象
private Paint mPaint;
//背景矩形
private Rect mBound;
//颜色集合
List<String> colors=new ArrayList<String>();
public CustomView(Context context) {
this(context, null, 0);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获得自定义属性集合
TypedArray typeArray=context.getTheme()
.obtainStyledAttributes(attrs,R.styleable.CustomView,defStyleAttr,0);
//遍历属性集合,获得相关属性
Log.i("wangsongbin", typeArray.getIndexCount()+" "+typeArray.length());
int n=typeArray.getIndexCount();
for(int i=0;i<n;i++){
int attr=typeArray.getIndex(i);
Log.i("wangsongbin", attr+" ");
switch(attr){
case R.styleable.CustomView_titleText:
titleText=typeArray.getString(attr);
break;
case R.styleable.CustomView_titleTextColor:
titleTextColor=typeArray.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomView_titleTextSize://字体大小默认是sp所以要转化成为px类型
titleTextSize=typeArray.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
break;
}
}
typeArray.recycle();//调用此方法主要是为了缓存,是的次资源可以被重复利用
//取完自定义属性后可以根据字符串长度,和字体的大小来确定背景矩形的大小
mPaint=new Paint();
mPaint.setTextSize(titleTextSize);
mBound=new Rect();
mPaint.getTextBounds(titleText, 0, titleText.length(), mBound);
//设置监听器,使得每次点击,都随机出现4个不同的数字!
this.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
titleText=getRondomText();
postInvalidate();//重新绘制
}
});
colors.add("#ff0000");//红色
colors.add("#0000ff");//蓝色
colors.add("#008000");//绿色
colors.add("#00ff00");//浅绿色
colors.add("#ffA500");//橘色
colors.add("#A52a2a");//棕色
colors.add("#000000");//黑色
colors.add("#A9A9A9");//灰色
colors.add("#9400d3");//紫色
colors.add("#FFd700");//黄色
}
private String getRondomText() {
Set<Integer> set=new HashSet<Integer>();
Random random=new Random();
while(set.size()<4){
int n=random.nextInt(10);
set.add(n);
}
StringBuffer buf=new StringBuffer();
for(Integer i:set){
buf.append(i);
}
return buf.toString();
}
4,调整布局,重新设置控件的宽高
//调整布局
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width=0;
int height=0;
/**
* 设置高宽
*/
int specMode=MeasureSpec.getMode(widthMeasureSpec);
int specSize=MeasureSpec.getSize(widthMeasureSpec);
switch(specMode){
case MeasureSpec.AT_MOST://一般为WARP_CONTENT
width=getPaddingLeft()+getPaddingRight()+mBound.width();
break;
case MeasureSpec.EXACTLY:
width=getPaddingLeft()+getPaddingRight()+specSize;
break;
}
specMode=MeasureSpec.getMode(heightMeasureSpec);
specSize=MeasureSpec.getSize(heightMeasureSpec);
switch(specMode){
case MeasureSpec.AT_MOST:
height=getPaddingBottom()+getPaddingTop()+mBound.height();
break;
case MeasureSpec.EXACTLY:
height=getPaddingBottom()+getPaddingTop()+specSize;
break;
}
setMeasuredDimension(width, height);//设置控件的高宽
}
5,绘制控件
//在画布上画图
@Override
protected void onDraw(Canvas canvas) {
/**
* 1,先画背景
* 2,画数字
* 3,在数字上画两条线
*/
mPaint.setColor(Color.YELLOW);
canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint);
char[] chars=titleText.toCharArray();
//小知识点,如果没有调用measure(widthMeasureSpec, heightMeasureSpec);方法,getMeasuredWidth()与getWidth()是相同的
mPaint.setColor(titleTextColor);
for(int i=0;i<chars.length;i++){
mPaint.setColor(Color.parseColor(colors.get(Integer.parseInt(""+chars[i]))));
canvas.drawText(chars, i, 1, getWidth()/2-mBound.width()/2+i*mBound.width()/chars.length, getHeight()/2+mBound.height()/2,mPaint);
}
Random random=new Random();
canvas.drawLine(0, getHeight()*random.nextInt(5)/5, getWidth(), getHeight()*random.nextInt(5)/5, mPaint);
canvas.drawLine(0, getHeight()*random.nextInt(5)/5, getWidth(), getHeight()*random.nextInt(5)/5, mPaint);
}
6,在布局中应用我们自定控件!
注意布局中的代码:xmlns:wang="http://schemas.android.com/apk/res/com.wang.customview1"
com.wang.customview1是我们的项目包名,一定要加上否则,及没办法设置自定义的属性
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:wang="http://schemas.android.com/apk/res/com.wang.customview1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.wang.customview1.MainActivity" >
<com.wang.customview1.view.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_centerInParent="true"
wang:titleTextSize="20sp"
wang:titleText="9475"
wang:titleTextColor="#ff0000"/>
</RelativeLayout>