自定义View实现验证码效果

来源:互联网 发布:cnnic最新数据 编辑:程序博客网 时间:2024/05/11 05:00

今天我们要实现的是,自定义一个控件,控件会随机展示4个数字,和两条横线,点击会展示新的4个数据和两条横线。

如图,第一张图式开始展示的样子,第二张图是点击后展示的样子!功能很简单,但这只是刚刚起步!

现在和大家讲讲具体的实现步骤!

1,在res/values/目录下面创建一个attrs.xml文件来声明自定义的属性!

2,声明一个类继承View

3,重写构造方法,在构造方法中拿到自定义的属性

4,重写onMeasure()方法,调整布局

5,重写onDraw();方法,绘制控件

6,在布局空应用自定控件

首先我们看到第一步,我们声明了自定义属性:控件文本显示内容,文本的大小,文本的颜色!

<?xml version="1.0" encoding="utf-8"?><resources>    <attr name="titleTextSize" format="dimension"></attr>    <attr name="titleText" format="string"></attr>    <attr name="titleTextColor" format="color"></attr>        <declare-styleable name="CustomView">        <attr name="titleTextSize"/>        <attr name="titleText"/>        <attr name="titleTextColor"/>     </declare-styleable>    </resources>

2,3我们重写了构造方法,注意一个参数的构造方法,和两个参数的构造方法我们都让其调用三个参数的构造方法,这样三个参数的构造方法是必须执行的,这样我们就在

三个参数的构造方法中,拿到我们自定义的属性值。

public class CustomView extends View{//文本显示内容private String titleText;//字体颜色private int titleTextColor;//字体大小private int titleTextSize; //画笔对象private Paint mPaint;//背景矩形private Rect mBound;//颜色集合List<String> colors=new ArrayList<String>();public CustomView(Context context) {this(context, null, 0);}public CustomView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);//获得自定义属性集合TypedArray typeArray=context.getTheme().obtainStyledAttributes(attrs,R.styleable.CustomView,defStyleAttr,0);    //遍历属性集合,获得相关属性Log.i("wangsongbin", typeArray.getIndexCount()+"  "+typeArray.length());int n=typeArray.getIndexCount();for(int i=0;i<n;i++){int attr=typeArray.getIndex(i);Log.i("wangsongbin", attr+"  ");switch(attr){case R.styleable.CustomView_titleText:titleText=typeArray.getString(attr);break;case R.styleable.CustomView_titleTextColor:titleTextColor=typeArray.getColor(attr, Color.BLACK);break;case R.styleable.CustomView_titleTextSize://字体大小默认是sp所以要转化成为px类型titleTextSize=typeArray.getDimensionPixelSize(attr,                  (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));break;}} typeArray.recycle();//调用此方法主要是为了缓存,是的次资源可以被重复利用  //取完自定义属性后可以根据字符串长度,和字体的大小来确定背景矩形的大小 mPaint=new Paint(); mPaint.setTextSize(titleTextSize); mBound=new Rect(); mPaint.getTextBounds(titleText, 0, titleText.length(), mBound);  //设置监听器,使得每次点击,都随机出现4个不同的数字! this.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {titleText=getRondomText();postInvalidate();//重新绘制}}); colors.add("#ff0000");//红色colors.add("#0000ff");//蓝色    colors.add("#008000");//绿色colors.add("#00ff00");//浅绿色colors.add("#ffA500");//橘色colors.add("#A52a2a");//棕色colors.add("#000000");//黑色colors.add("#A9A9A9");//灰色colors.add("#9400d3");//紫色colors.add("#FFd700");//黄色}private String getRondomText() {Set<Integer> set=new HashSet<Integer>();Random random=new Random();while(set.size()<4){int n=random.nextInt(10);set.add(n);}    StringBuffer buf=new StringBuffer();    for(Integer i:set){    buf.append(i);    }return buf.toString();}

4,调整布局,重新设置控件的宽高

//调整布局@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    int width=0;    int height=0;    /**     * 设置高宽     */    int specMode=MeasureSpec.getMode(widthMeasureSpec);    int specSize=MeasureSpec.getSize(widthMeasureSpec);    switch(specMode){    case MeasureSpec.AT_MOST://一般为WARP_CONTENT    width=getPaddingLeft()+getPaddingRight()+mBound.width();    break;    case MeasureSpec.EXACTLY:    width=getPaddingLeft()+getPaddingRight()+specSize;    break;    }        specMode=MeasureSpec.getMode(heightMeasureSpec);    specSize=MeasureSpec.getSize(heightMeasureSpec);    switch(specMode){    case MeasureSpec.AT_MOST:    height=getPaddingBottom()+getPaddingTop()+mBound.height();    break;    case MeasureSpec.EXACTLY:    height=getPaddingBottom()+getPaddingTop()+specSize;    break;    }    setMeasuredDimension(width, height);//设置控件的高宽}


5,绘制控件

//在画布上画图@Overrideprotected void onDraw(Canvas canvas) {/** * 1,先画背景 * 2,画数字 * 3,在数字上画两条线 */mPaint.setColor(Color.YELLOW);canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint);char[] chars=titleText.toCharArray();//小知识点,如果没有调用measure(widthMeasureSpec, heightMeasureSpec);方法,getMeasuredWidth()与getWidth()是相同的mPaint.setColor(titleTextColor);for(int i=0;i<chars.length;i++){mPaint.setColor(Color.parseColor(colors.get(Integer.parseInt(""+chars[i]))));canvas.drawText(chars, i, 1, getWidth()/2-mBound.width()/2+i*mBound.width()/chars.length, getHeight()/2+mBound.height()/2,mPaint);}Random random=new Random();canvas.drawLine(0, getHeight()*random.nextInt(5)/5, getWidth(), getHeight()*random.nextInt(5)/5, mPaint);canvas.drawLine(0, getHeight()*random.nextInt(5)/5, getWidth(), getHeight()*random.nextInt(5)/5, mPaint);}


6,在布局中应用我们自定控件!

     注意布局中的代码:xmlns:wang="http://schemas.android.com/apk/res/com.wang.customview1"

     com.wang.customview1是我们的项目包名,一定要加上否则,及没办法设置自定义的属性

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:wang="http://schemas.android.com/apk/res/com.wang.customview1"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.wang.customview1.MainActivity" >    <com.wang.customview1.view.CustomView         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:padding="10dp"        android:layout_centerInParent="true"        wang:titleTextSize="20sp"        wang:titleText="9475"        wang:titleTextColor="#ff0000"/></RelativeLayout>


 


源码下载
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0 0
原创粉丝点击