前言:
写了几篇博文,说实话自己很不满意,都觉得很空洞,写的也不是很好,只能硬着头皮继续写,写多了希望能好些,这一系列都是基础+练手系列,大神无视,不管怎么样,希望能对大家有点帮助吧。
本系列主要是介绍一些使用绘制view方式来自定义view实现的一些效果,很多是我之前学别人实现的一些效果,作为基础入门篇。
概要:
记得之前学习hy大神的博文,大神说自定义VIew三大步骤:
1)自定义View的属性;
2)在构造方法中获取到属性;
3)重写onMeasure,onDraw,onLayout方法。
我一直秉承着大神的意志学习前进着,觉得还是蛮有用的,至少不会无从下手。本文将实现一个类似点击随机生成验证码的效果,比较简单。效果如图:
正文:
首先分析下我们会用到的属性,这里需要用到按钮背景色,文字颜色,字体大小。现在我们开始自定义属性,在values文件夹下创建一个attrs.xml文件,在里面定义我们的属性,声明我们的样式。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyViewAttrs">
<attr name="bgColor" format="color">#dddddd</attr>
<attr name="textColor" format="color">#ff0000</attr>
<attr name="textSize" format="dimension">30</attr>
</declare-styleable>
</resources>
这里format是取值类型。
有:string,color,demension,integer,enum,reference,float,boolean,fraction,flag。
现在声明自定义View,在布局文件中引入自定义View。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.example.liujibin.testmyview1"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.liujibin.testmyview1.MainActivity">
<com.example.liujibin.testmyview1.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
在声明的View中重写构造函数,这里因为要获取属性,所以我们设置默认调用含三个参数的构造函数。
public class MyView extends View {
//背景色
private int bgColor;
//文字色
private int textColor;
//文字大小
private int textSize;
public MyView(Context context) {
this(context,null);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MyViewAttrs,defStyleAttr,0);
bgColor = ta.getColor(R.styleable.MyViewAttrs_bgColor, Color.BLACK);
textColor = ta.getColor(R.styleable.MyViewAttrs_textColor,Color.WHITE);
textSize = ta.getDimensionPixelSize(R.styleable.MyViewAttrs_textSize,30);
ta.recycle();
}
}
TypedArray要记得释放。
然后重写onMeasure,onDraw,这里用不到onLayout。绘制View,还需要画笔(Paint)和画布(Canvas),画布在onDraw中有封装,直接用就好了,我们自己创建一个Paint对象。因为要在指定区域内绘制文字,所以我们还需要创建Rect对象,在构造函数中实例化,不要在onDraw中实例化。
private Paint paint;
private Rect r;
paint = new Paint();
r = new Rect();
下面我们先来设置画笔属性,绘制背景框:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制矩形区域
paint.setColor(bgColor);
paint.setStrokeWidth(3);
paint.setAntiAlias(true);
canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);
}
效果如图:
我们发现这个区域是全屏的,我们不需要这么大,只需要按钮大小,此时就需要用到onMeasure了。根据模式设置默认大小。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(widthMode == MeasureSpec.EXACTLY){
}else{
widthSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,300,getResources().getDisplayMetrics());
}
if(heightMode == MeasureSpec.EXACTLY){
}else{
heightSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,200,getResources().getDisplayMetrics());
}
setMeasuredDimension(widthSize,heightSize);
}
此时效果:
然后我们需要给画笔设置文字,设置字体,获取文字的宽高。
private String str = "4232";
//获取文字宽高,绘制文字
paint.setTextSize(textSize);
paint.setColor(textColor);
paint.getTextBounds(str,0,str.length(),r);
canvas.drawText(str,getWidth()/2-r.width()/2,getHeight()/2+r.height()/2,paint);
效果如图:
下面需要实现点击变化文字,实现View的点击事件,我们这里取四位随机数,然后点击后设置给绘制的字符串。
//生成随机字符串
private String changeText(){
Random random = new Random();
String num = "";
for(int i = 0;i < 4;i++){
num = num + random.nextInt(10);
}
return num;
}
现在我们要的效果就实现了。
附上全部View的代码:
public class MyView extends View implements View.OnClickListener{
//背景色
private int bgColor;
//文字色
private int textColor;
//文字大小
private int textSize;
private Paint paint;
private Rect r;
private String str = "4232";
public MyView(Context context) {
this(context,null);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MyViewAttrs,defStyleAttr,0);
bgColor = ta.getColor(R.styleable.MyViewAttrs_bgColor, Color.BLACK);
textColor = ta.getColor(R.styleable.MyViewAttrs_textColor,Color.WHITE);
textSize = ta.getDimensionPixelSize(R.styleable.MyViewAttrs_textSize,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
30,getResources().getDisplayMetrics()));
ta.recycle();
setOnClickListener(this);
paint = new Paint();
r = new Rect();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(widthMode == MeasureSpec.EXACTLY){
}else{
widthSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,200,getResources().getDisplayMetrics());
}
if(heightMode == MeasureSpec.EXACTLY){
}else{
heightSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,100,getResources().getDisplayMetrics());
}
setMeasuredDimension(widthSize,heightSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制矩形区域
paint.setColor(bgColor);
paint.setStrokeWidth(3);
paint.setAntiAlias(true);
canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);
//获取文字宽高,绘制文字
paint.setTextSize(textSize);
paint.setColor(textColor);
paint.getTextBounds(str,0,str.length(),r);
canvas.drawText(str,getWidth()/2-r.width()/2,getHeight()/2+r.height()/2,paint);
}
//生成随机字符串
private String changeText(){
Random random = new Random();
String num = "";
for(int i = 0;i < 4;i++){
num = num + random.nextInt(10);
}
return num;
}
@Override
public void onClick(View view) {
str = changeText();
invalidate();
}
}