Android自定义View 做个简单的验证码控件

首先感谢鸿洋大神,因为我看了他的文章后才写了这篇博文。
传送门:http://blog.csdn.net/lmj623565791/article/details/24252901

从15年工作到现在两年多了,从一个什么都不会的小菜鸟到现在会写点小程序的老菜鸟。两年来,做了十来个项目,有大有小,有团队开发也有单独开发,虽然比刚入职有了进步,但是总体来说总是差强人意,重复的用轮子,让自己的代码千篇一律毫无亮点。

两年来虽然自己不是完全没有写过自定义控件,但是也是极少写的,一直都感觉自定义控件十分复杂,写起来也比较费脑子(本人懒癌晚期患者),能不写就不写,随便百度一个相似控件,改改能用就行,不考虑是否与界面一致,色值是否协调,这也让我在开发中吃了不少亏,界面不协调改,色值相差大改,虽然在使用轮子中减少了工作量,但是在后续修改中也花费了不少工作时间,如果你是新人,千万不要学我。

虽然在开发界常说不要重复造轮子,但是呢这句话得这样看,不重复是对的,但是怎么造轮子这是门技术,这是需要我们学习的

第一步
自定义view的属性:
在你的项目/res/velues目录下新增attrs.xml,在这里你可以定义你需要定义的属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--设置参数 -->
    <attr name="authCodeText" format="string"/><!--验证码显示值-->
    <attr name="authCodeBackground" format="color"/><!--验证码背景-->
    <attr name="authCodeTextSize" format="dimension"/><!--验证码位数-->

    <!--声明-->
    <declare-styleable name="AuthCodeUtils">
        <attr name="authCodeText"/>
        <attr name="authCodeBackground"/>
        <attr name="authCodeTextSize"/>
    </declare-styleable>
</resources>

第二步
获得自定义样式

写一个工具类并继承View(AuthCodeUtils),在构造方法中调用我们的样式

public class AuthCodeUtils extends View {
    private String authCodeText;//文本
    private int authCodeBackground;//背景颜色
    private int authCodeSize;//验证码长度

    private Rect mRect;//绘制矩形
    private Paint mPaint;//

    //构造方法
    public AuthCodeUtils(Context context, AttributeSet attributeSet) {
        super(context, attributeSet, 0);
        initializeProperty(context, attributeSet);
    }

    /**
     * 初始化属性
     *
     * @param context
     * @param attributeSet
     */
    private void initializeProperty(Context context, AttributeSet attributeSet) {
        TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.TestTextUtil);
        //获取typedArray长度
        int num = typedArray.getIndexCount();
        for (int i = 0; i < num; i++) {
            //获取属性ID
            int id = typedArray.getIndex(i);
            switch (id) {
                case R.styleable.TestTextUtil_authCodeText:
                    authCodeText = typedArray.getString(id);
                    break;
                case R.styleable.TestTextUtil_authCodeTextSize:
                    authCodeSize = typedArray.getDimensionPixelSize(id, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.TestTextUtil_authCodeBackground:
                    authCodeBackground = typedArray.getColor(id, Color.YELLOW);
                    break;
            }
        }
        typedArray.recycle();
        //获取文本的长和宽
        mPaint = new Paint();
        mPaint.setTextSize(authCodeSize);
        mRect = new Rect();
        mPaint.getTextBounds(authCodeText, 0, authCodeText.length(), mRect);
    }

然后重新onDraw方法

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //添加背景色
        mPaint.setColor(Color.YELLOW);
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
        //字体颜色
        mPaint.setColor(authCodeBackground);
        canvas.drawText(authCodeText, getWidth() / 2 - mRect.width() / 2, getHeight() / 2 + mRect.height() / 2, mPaint);
    }

然后在布局文件中声明并调用

<?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-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<!--注意此句xmlns:custom="http://schemas.android.com/apk/res-auto",如果不写,则无法获得我们自定义的属性-->
    <!--声明并调用-->
    <cm.cui.publicbase.test.AuthCodeUtils
        android:id="@+id/testText"
        android:layout_width="70dp"
        android:layout_height="30dp"
        android:layout_centerInParent="true"
        android:padding="10dp"
        custom:authCodeBackground="@color/colorAccent"
        custom:authCodeText="3712"
        custom:authCodeTextSize="16sp"/>
</RelativeLayout>

运行程序,效果如图
这里写图片描述

第三步

重写onMeasure方法

这里是抄的鸿洋大神的代码,不过我加了注释和修改了一些地方,差不多意思就是这样

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取控件宽高的显示模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        //获取宽高的尺寸值  固定值的宽度
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int width;
        int height;

//        MeasureSpec父布局传递给后代的布局要求 包含 确定大小和三种模式
//        EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
//        AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
//        UNSPECIFIED:表示子布局想要多大就多大,很少使用
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            mPaint.setTextSize(authCodeSize);
            mPaint.getTextBounds(authCodeText, 0, authCodeText.length(), mRect);
            float textWidth = mRect.width();
            int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
            width = desired;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            mPaint.setTextSize(authCodeSize);
            mPaint.getTextBounds(authCodeText, 0, authCodeText.length(), mRect);
            float textHeight = mRect.height();
            int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
            height = desired;
        }
        //设置测量的宽高
        setMeasuredDimension(width, height);
    }

编写噪点和划线方法,大意如下图

   //随机生成小圆点坐标
    private int[] getPoint(int height, int width) {
        int[] tempCheckNum = {0, 0};
        tempCheckNum[0] = (int) (Math.random() * width);
        tempCheckNum[1] = (int) (Math.random() * height);
        return tempCheckNum;
    }

    //随机生成线线
    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;
    }

调用生成的噪点和划线方法

 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, mPaint);
        }

        for (int i = 0; i < 50; i++) {
            point = getPoint(height, width);
            canvas.drawCircle(point[0], point[1], 2, mPaint);
        }

        for (int i = 0; i < 30; i++) {
            point = getPoint(height, width);
            canvas.drawCircle(point[0], point[1], 3, mPaint);
        }

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

请自行添加点击事件……..

运行程序

这里写图片描述

Demo:代码地址,点我传送

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android定义View是指基于Android原生件的一种扩展,可以根据自己的需求和设计规范来创建更加个性化和独特的件。而歌词件是一种针对音乐播放器或者视频播放器等应用场景中的需求,用于显示音乐或者视频的歌词的件。 Android定义View歌词件的实现思路如下: 1. 首先需要自定义一个View,并继承自View或者其子类,如TextView。 2. 在自定义View中重写onDraw方法,在其中实现绘制歌词的逻辑。 3. 在onDraw方法中,使用Canvas对象进行绘制,可以使用drawText方法绘制歌词文本,也可以使用drawBitmap方法绘制图片背景等。 4. 可以通过自定义属性,如字体大小、字体颜色、歌词滚动速度等,来对歌词件进行配置。 5. 如果需要实现歌词的滚动效果,可以使用ValueAnimator或者Scroller来实现歌词的平滑滚动。 6. 如果需要实现点击歌词跳转播放进度的功能,可以通过添加点击事件监听器,在触摸事件中判断点击位置对应的歌词行,并根据歌词的时间戳跳转到指定的播放进度。 总结来说,Android定义View歌词件的实现需要重写onDraw方法进行绘制,可以通过Canvas对象进行绘制文本或者图像,通过自定义属性进行配置,使用动画或者滚动实现歌词的平滑滚动,通过监听触摸事件实现点击歌词跳转播放进度的功能。通过以上步骤,我们可以创建一个个性化的歌词件,满足不同应用场景的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值