Android custom View basic series one (click to randomly generate verification code effect)

Foreword:

I wrote a few blog posts. To be honest, I was very dissatisfied. They all felt empty and the writing was not very good. I could only bite the bullet and continue writing. I hope it will be better if I write more. This series is a basic + practice series. God ignores it, no matter what, I hope it can be of some help to everyone.

This series mainly introduces some effects of using the drawing view method to customize the view. Many of them are some effects that I have learned from others before, as a basic introduction.

overview:

I remember studying the blog post of Master Hy before. He said there are three major steps to customize VIew:

1) Customize View properties;

2) Obtain the properties in the constructor;

3) Override onMeasure, onDraw, onLayout methods.

I have been learning and moving forward according to the will of the great master, and I think it is quite useful, at least I won't be unable to start. This article will achieve an effect similar to clicking to randomly generate a verification code, which is relatively simple. The effect is as shown in the figure:


text:

First, let’s analyze the attributes we will use. Here we need to use the button background color, text color, and font size. Now we start to customize attributes, create an attrs.xml file in the values ​​folder, define our attributes in it, and declare our styles.

<?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>
Here format is the value type. There are: string, color, demension, integer, enum, reference, float, boolean, fraction, flag.

Now declare the custom View and introduce the custom View in the layout file.

<?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>
Rewrite the constructor in the declared View. Because we want to get the properties, we set the default to call the constructor with three parameters.

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 must remember to release.

Then rewrite onMeasure, onDraw, onLayout is not used here. To draw a View, you also need a paintbrush (Paint) and a canvas (Canvas). The canvas is encapsulated in onDraw, so just use it directly. We create a Paint object ourselves. Because we want to draw text within the specified area, we also need to create a Rect object and instantiate it in the constructor, not in onDraw.

private Paint paint;

private Rect r;

paint = new Paint();
r = new Rect();
Next we first set the brush properties and draw the background box:

@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);

    }


The effect is as shown in the figure:



We found that this area is full screen. We don't need it to be so big. We only need the button size. At this time, we need to use onMeasure. Sets the default size based on the mode.

@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);
    }
The effect at this time:


Then we need to set the text for the brush, set the font, and get the width and height of the text.

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);

The effect is as shown in the figure:



Next, we need to realize the click change text and the click event of the View. Here we take four random numbers, and then set the string to be drawn after clicking.

//生成随机字符串
    private String changeText(){

        Random random = new Random();
        String num = "";
        for(int i = 0;i < 4;i++){
            num = num + random.nextInt(10);
        }

        return num;
    }
Now the effect we want is achieved.

Attached are the codes for all Views:

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();
    }
}







Guess you like

Origin blog.csdn.net/liujibin1836591303/article/details/53813391