android自定义View基础系列一(点击随机生成验证码效果)

前言:

写了几篇博文,说实话自己很不满意,都觉得很空洞,写的也不是很好,只能硬着头皮继续写,写多了希望能好些,这一系列都是基础+练手系列,大神无视,不管怎么样,希望能对大家有点帮助吧。

本系列主要是介绍一些使用绘制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();
    }
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值