自定义View实现验证码效果

本文详细介绍了如何自定义一个Android控件,该控件能随机展示4个数字和两条横线,并在点击后更新展示内容。通过创建attrs.xml文件声明属性,重写View类的方法调整布局和绘制控件,最后在布局中应用自定义控件。重点在于构造方法获取自定义属性,以及在onDraw()方法中实现动态显示效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天我们要实现的是,自定义一个控件,控件会随机展示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() {
			
			@Override
			public 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,调整布局,重新设置控件的宽高

//调整布局
	@Override
	protected 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,绘制控件

//在画布上画图
	@Override
	protected 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>


 


源码下载
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值