android开发步步为营之93:android自定义view开发之一(验证码生成器)
来源:互联网 发布:成龙在国外有多火 知乎 编辑:程序博客网 时间:2024/04/29 00:24
在android开发的过程中,你会发现,如果只是使用系统自带的那些控件是无法满足产品日益变化的需求的,所以我们经常会用到自定义view,自定义view有三种,第一种最基础的组合控件,将android现有的控件组合在一起,比如在页面头部做一个通用的头部,一个退出image+标题textview,这种最简单。第二种就是继承某个控件,比如继承某个button,让这个button有点击或长按效果,第三种就是直接继承View父类,自己画一个View出来,个人认为这是相对前两种更难实现的。但是通过一个demo下来,发现说难也不难的,主要要做以下几步:
1、设置attr自定义属性
2、自定义view构造函数中获取自定义view属性的值
3、重写onMeasure(int widthMeasureSpec, int heightMeasureSpec)绘制控件高度和宽度
4、重写protected void onDraw(Canvas canvas)绘制控件
本实验做的是一个自定义的验证码生成器,字母和数字的组合,可以设置是否包含字母或数字,以及字母和数字的个数,先看看效果,设置字母和数字都包含,然后各有3个:
上面的验证码就是本次实验生成的自定义view。
好的,开始我们的实验。
第一步、设置attr自定义属性
在attrs.xml中增加
<declare-styleable name="ValidateView"> <attr name="showLetter" format="boolean" /> <attr name="showNumber" format="boolean" /> <attr name="LetterNum" format="integer"/> <attr name="numberNum" format="integer"/> <attr name="textSize" format="integer"/> </declare-styleable>
第二步、自定义view构造函数中获取自定义view属性的值
第三步、重写onMeasure(int widthMeasureSpec, int heightMeasureSpec)绘制控件高度和宽度
第四步、重写protected void onDraw(Canvas canvas)
以上几步见自定义ValidateView.java
package com.figo.study.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.util.AttributeSet;import android.util.TypedValue;import android.view.View;import com.figo.study.R;import com.figo.study.utils.CommonUtil;import java.util.ArrayList;import java.util.Collections;import java.util.Random;/** * Created by figo on 16/02/04. */public class ValidateView extends View implements View.OnClickListener { boolean mShowLetter = false; boolean mShowNum = false; int mLetterNum = 0; int mNumberNum = 0; String[] mLetters = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; String[] mNumbers = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; ArrayList<String> mArrayList; String mText; private Rect mTextBounds; Paint mPaint; int mTextSize; public ValidateView(Context context) { super(context); } public ValidateView(Context context, AttributeSet attrs) { super(context, attrs); //获取自定义属性的值,在OnDraw的时候使用 TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.ValidateView, 0, 0); try { mShowLetter = a.getBoolean(R.styleable.ValidateView_showLetter, false); mLetterNum = a.getInteger(R.styleable.ValidateView_LetterNum, 0); mShowNum = a.getBoolean(R.styleable.ValidateView_showNumber, false); mNumberNum = a.getInteger(R.styleable.ValidateView_numberNum, 0); mTextSize = a.getInteger(R.styleable.ValidateView_textSize, 0); } finally { a.recycle(); } //首次生成一串验证码 generateValidateCode(); mPaint = new Paint(); //设置画笔 mPaint.setColor(Color.parseColor("#80FF0000")); mPaint.setTextSize(80); mTextBounds = new Rect(); setOnClickListener(this); } /** * @param widthMeasureSpec * @param heightMeasureSpec 如果android:layout_width="200dp" * android:layout_height="100dp"设置了具体的值这个方法不用重写 * wrap_content/match_parent,默认会全屏显示这个控件 * 所以设置成wrap_content需要重写这个方法,重新测量宽度和高度 */ @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); int width; int height; mPaint.setTextSize(mTextSize); mPaint.getTextBounds(mText, 0, mText.length(), mTextBounds); if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { width = (int) (getPaddingLeft() + mTextBounds.width() + getPaddingRight()); } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { height = (int) (getPaddingTop() + mTextBounds.height() + getPaddingBottom()); } //设置高度 setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //画背景颜色 canvas.drawColor(Color.parseColor("#80123456")); //将文字绘在正中 mPaint.getTextBounds(mText, 0, mText.length(), mTextBounds); float textWidth = mTextBounds.width(); float textHeight = mTextBounds.height(); canvas.drawText(mText, getWidth() / 2 - textWidth / 2, getHeight() / 2 + textHeight / 2, mPaint); } @Override public void onClick(View v) { generateValidateCode(); //触发onDraw,重绘view invalidate(); } private void generateValidateCode() { if (mArrayList == null) { mArrayList = new ArrayList<String>(); } else { mArrayList.clear(); } if (mShowLetter) { for (int a = 0; a < mLetterNum; a++) { mArrayList.add(mLetters[new Random().nextInt(26)]); } } if (mShowNum) { for (int b = 0; b < mNumberNum; b++) { mArrayList.add(mNumbers[new Random().nextInt(10)]); } } //乱序排列 Collections.shuffle(mArrayList); //写文字 StringBuffer buffer = new StringBuffer(); for (int a = 0; a < mArrayList.size(); a++) { buffer.append(mArrayList.get(a)); } mText = buffer.toString(); } public String getText() { return mText; }}
第五步、activity页面使用自定义view
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" tools:context="com.figo.study.activity.CustomViewActivity"> <com.figo.study.view.ValidateView android:id="@+id/validate_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="15dp" custom:LetterNum="3" custom:numberNum="3" custom:textSize="60" custom:showLetter="true" custom:showNumber="true" /> <Button android:id="@+id/btn_current" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="获取当前验证码" /></LinearLayout>
- android开发步步为营之93:android自定义view开发之一(验证码生成器)
- android开发步步为营之91:自定义AlertDialog
- android开发步步为营之28:自定义Menu
- android开发步步为营之95:自定义dialog去掉白色边框
- android开发步步为营之99:使用自定义字体
- android开发步步为营之98:android studio使用技巧之一(如何清理不需要的文件)
- android开发步步为营之2:开发自定义进度条对话框
- android开发步步为营之25:开发自定义进度条对话框
- android开发步步为营之81:android图片处理技术之一(截取与缩放)
- android开发步步为营之3:自定义控件之手势签名
- android开发步步为营之64:PopupWindow实现自定义弹出菜单
- android开发步步为营之78:自定义样式ProgressBar
- android开发步步为营之88:基于LruCache和AsyncTask的网络相册开发
- android开发之自定义View
- Android开发之自定义View
- android开发步步为营之96:android两种常用截图技术
- android开发步步为营之56:Android开发常见问题技术点总结之一
- Android开发之自定义View(视图)
- mongodb搭建校内搜索引擎——爬取网页文本
- 【总结】黎明就在眼前——半年总结(2016年2月4日)
- swift基础(二):字符串和字符
- WEB Service 下实现大数据量的传输
- swift基础(三):流程控制:循环语句
- android开发步步为营之93:android自定义view开发之一(验证码生成器)
- 解hash引用
- LeakCanary: 让内存泄露无所遁形
- Wunder Fund Round 2016 (Div. 1 + Div. 2 combined) ---补题
- ISO语言代码和国家代码+Locale常量+ISO货币符号
- iOS 发布后的bug跟踪
- win7的aero特效无法启动的处理方法
- Python全局变量
- java验证码