码迷,mamicode.com
首页 > 其他好文 > 详细

仿带噪点和横线的验证码自定义View

时间:2016-05-06 16:05:52      阅读:244      评论:0      收藏:0      [点我收藏+]

标签:

1.自定义view的步骤:

a.在values/attrs.xml文件中创建自定义的属性;
b.自定义view,在view的构造方法中获取到自定义的属性;
c.重写onDraw()方法;
d.重写onMeasure()方法。

在values/attrs.xml文件中创建自定义的属性

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="texttitle" format="string"/>
    <attr name="textcolor" format="color"/>
    <attr name="textsize" format="dimension"/>


    <declare-styleable name="MyTextView">
        <attr name="textsize"/>
        <attr name="texttitle"/>
        <attr name="textcolor"/>
    </declare-styleable>
</resources>

设置了一个自定义的textview,设置了字体,颜色和大小的属性。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:keke="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.best.keke.mycustondemo.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World!"
        keke:textcolor="#78101ff1"
        keke:textsize= "30sp"
        android:layout_centerInParent="true"
        keke:texttitle="你好啊啊"/>
</RelativeLayout>

注意:在此处一定要声明自己的命名空间。

xmlns:keke="http://schemas.android.com/apk/res-auto"

自定义view,在view的构造方法中获取到自定义的属性

public class MyCustomView extends TextView {

    private String texttitle;
    private int textcolor;
    private int textSize;
    private Paint paint;
    private Rect rect;

    public MyCustomView(Context context) {
        this(context, null);
    }

    public MyCustomView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 获取到自定义的样式的属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyTextView, defStyleAttr, 0);
        int count = array.getIndexCount();
        for (int i = 0; i < count; i++) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.MyTextView_textcolor:
                    // 设置默认的颜色为蓝色
                    textcolor = array.getColor(attr,Color.BLUE);
                    break;

                case R.styleable.MyTextView_textsize:
                    // 设置字体的大小,默认的是16sp
                    textSize = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                            16, getResources().getDisplayMetrics()));
                    break;

                case R.styleable.MyTextView_texttitle:
                    // 设置字体的标题
                    texttitle = array.getString(attr);
                    break;
            }
        }
        // 调用此方法,方便重复利用该view中的属性。Recycles the TypedArray, to be re-used by a later caller. After calling this function you must not ever touch the typed array again.
        array.recycle();

        // 获取绘制文本的宽高

        paint = new Paint();
        paint.setTextSize(textSize);
        paint.setColor(textcolor);
        // 创建一个矩形
        rect = new Rect();
        /**
         * @param text  String to measure and return its bounds 要测量的文字
         * @param start Index of the first char in the string to measure    测量的起始位置
         * @param end   1 past the last char in the string measure  测量的最后一个字符串的位置
         * @param bounds Returns the unioned bounds of all the text. Must be    rect对象
         *               allocated by the caller.
         */
        paint.getTextBounds(texttitle, 0, texttitle.length(), rect);
    }

重写onDraw(),onMeasure()方法

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.GREEN);
        // 设置矩形的长宽高
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
        paint.setColor(textcolor);
        //drawRect(float left, float top, float right, float bottom,Paint paint)
        canvas.drawText(texttitle, getWidth() / 2 - rect.width() / 2, getHeight() / 2 + rect.height() / 2, paint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }

public void drawRect(float left, float top, float right, float bottom,Paint paint)

说明:绘制一个矩型。需要注明的是绘制矩形的参数和Java中的方法不一样。

drawRect()方法的参数图解说明如下:
技术分享

当我们把android:layout_width=”100dp”,android:layout_height=”100dp”的布局改成wrap_cotent的时候,发现样子是这样的:
技术分享

改成是match_parent时是这样的:
技术分享

可以看出,要让自定义的view支持wrap_content属性,那么久必须要重写onMeasure()方法来制定wrap_content的大小。

这是因为view类中默认的onMeasure()方法只支持EXACTLY模式,所以控件如果在自定义的时候不重写onMeasure()方法的话,那么就使用EXACTLY模式,控件只能响应你所制定的具体宽高值或者是match_parent属性,如果要支持wrap_contaent属相,那么久必须要重写onMeasure()方法。

android给我们提供了一个MeasureSpec类,来帮我们测量view,MeasureSpec是一个32位的int值,其中高两位是测量的模式,低30位使我们测量的大小:
测量的3中模式:
EXACTLY:精确模式,当我们的控件的layout_width或者layout_height属性为具体的属性值的到时候,比如layout_width=100dp,系统使用的是EXACTLY模式。

AT_MOST:最大值模式,当我们的控件的layout_width或者layout_height属性为wrap_content的时候,此时的控件的尺寸只要不超过父控件允许的最大尺寸即可。

UNSPECIFIED:非精确模式,不指定其大小测量模式,view想多大就多大,通常在绘制自定义view的时候才会使用。

重写onMeasure()方法

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 获取到宽高的测量模式以及测量值
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        Log.e("tag", "" + widthMode + widthSize);

        int heightMtode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        Log.e("tag", "" + heightMtode + heightSize);
        int width;
        int height;
        // 宽如果是精确测量
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize   ;
        } else {
            paint.setTextSize(textSize);
            paint.getTextBounds(texttitle, 0, texttitle.length(), rect);
            int textWidth = rect.width();
            int measureWidth = getPaddingLeft() + textWidth + getPaddingRight();
            width = measureWidth;
        }

        if (heightMtode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            paint.setTextSize(textSize);
            paint.getTextBounds(texttitle, 0, texttitle.length(), rect);
            float textHeight = rect.height();
            int measureHeight = (int) (getPaddingTop() + textHeight + getPaddingBottom());
            height = measureHeight;
        }

        // 重新设置空间的宽高
        setMeasuredDimension(width,height);
    }

重写onMeasure()方法之后的效果:
技术分享

为自定义的textview添加噪点和横线,仿照验证码的样式

在onDraw()方法中写划线和画圆点的方法。

// 获取到自定义的view宽高
        final int height = getHeight();
        final int width = getWidth();
        // 绘制小圆点
        int[] point;
        for (int i = 0; i < 100; i++) {
            point = getPoint(height, width);
             /**
             * drawCircle (float cx, float cy, float radius, Paint paint)
             * float cx:圆心的x坐标。
             * float cy:圆心的y坐标。
             * float radius:圆的半径。
             * Paint paint:绘制时所使用的画笔。
             */
            canvas.drawCircle(point[0], point[1], 1, paint);
        }

        int [] line;
        for(int i = 0; i < 100; i ++)
        {
            line = getLine(height, width);
            /**
             * startX:起始端点的X坐标。
             *startY:起始端点的Y坐标。
             *stopX:终止端点的X坐标。
             *stopY:终止端点的Y坐标。
             *paint:绘制直线所使用的画笔。
             */
            canvas.drawLine(line[0], line[1], line[2], line[3], paint);
        }
public  int[] getLine(int height, int width)
    {
        int [] tempCheckNum = {0,0,0,0};
        for(int i = 0; i < 4; i+=2)
        {
            tempCheckNum[i] = (int) (Math.random() * width);
            tempCheckNum[i + 1] = (int) (Math.random() * height);
        }
        return tempCheckNum;
    }

    private int[] getPoint(int height, int width) {
        int[] tempCheckNum = {0, 0, 0, 0};
        tempCheckNum[0] = (int) (Math.random() * width);
        tempCheckNum[1] = (int) (Math.random() * height);
        return tempCheckNum;
    }

样式如下:
技术分享

仿带噪点和横线的验证码自定义View

标签:

原文地址:http://blog.csdn.net/qq_24304811/article/details/51308663

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!