大佬教程收集整理的这篇文章主要介绍了Android自定义View实现验证码,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
本文章是基于鸿洋的Android 自定义View (一) 的一些扩展,以及对Android自定义View构造函数详解里面内容的一些转载。
首先我们定义一个declare-styleable标签declare-styleable标签的作用是给自定义控件添加自定义属性用的例如这样
(我们定义了文字的颜色,大小,长度,跟背景的颜色)
<declare-styleable name="CustomtitleView"> <attr name="titleColor" format="color" /> <attr name="titleSize" format="dimension" /> <attr name="titleBACkground" format="color" /> <attr name="titleLenth" format="Integer" /> </declare-styleable>
Android提供了自定义属性的@L_618_14@,其中的format的参数有
(reference、color、Boolean、dimension、float、Integer、String、fraction、enum、flag)
1.reference:资源ID:
如果设置了这个属性那么这个属性相当于@String|@drawable等调用资源文件的作用
2. color:
这个属性的作用为设置颜色值8或者6位的16进制的颜色值,如设置TextView的textColor等属性的作用相同(如#ff000设置为红色等)
3.Boolean:
这个参数的作用为设置true或者false
4.dimension:
这个参数的作用为设置尺寸值,如px、dip、dp、sp等
5.float:
这个参数的作用为设置浮点型数据
6.Integer:
这个参数的作用为设置整形数据
7.String:
这个参数的作用为设置字符串数据,如TextView的text属性
8.fraction:
这个参数的作用为设置百分比数据
9:enum:
这个参数相当于给这个attr的name属性设置固定的参数,如线性布局的orientation属性只能设置vertical或者horizontal
10:flag:
这个参数作用为:位或运算
1、自定义view的属性
2、在View的构造@L_618_14@中获得我们自定义的属性
3、重写onMeasure
4、重写onDraw
有的时候onMeasure@L_618_14@是不用重写的例如系统自带组件等
然后我们定义一下需要的属性
//文本 private StringBuffer mtitleText; //文本的颜色 privatE int mtitleColor; //文本的大小 privatE int mtitleSize; //背景颜色 privatE int mBACkground; //控制生成的随机字符串长度 privatE int mLenth; //绘制时控制文本绘制的范围 private Rect mBound; //画笔 private Paint mPaint; //随机数对象 private Random random = new Random(); //字符串边距 privatE int padding_left; //随机的值 String[] data = {"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","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","0","1","2","3","4","5","6","7","8","9"};
1、在代码中直接new一个自定义view实例的时候,会调用第一个构造函数.
2、在xml布局文件中调用自定义view的时候,会调用第二个构造函数.
3、在xml布局文件中调用自定义view,并且自定义标签中还有自定义属性时,这里调用的还是第二个构造函数.
也就是说,系统默认只会调用Custom View的前两个构造函数,至于第三个构造函数的调用,通常是我们自己在构造函数中主动调用的(例如,在第二个构造函数中调用第三个构造函数).
至于自定义属性的获取,通常是在构造函数中通过obtainStyledAttributes函数实现的。
public CustomtitleView(Context context) { this(context,null); } public CustomtitleView(Context context,AttributeSet attrs) { this(context,attrs,0); } public CustomtitleView(Context context,AttributeSet attrs,int defStyleAttr) { super(context,defStyleAttr); setOnClickListener(this); TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.CustomtitleView); int n = typedArray.geTindexCount(); for (int i = 0; i < n; i++) { int attr = typedArray.geTindex(i); switch (attr) { case R.styleable.CustomtitleView_titleColor: mtitleColor = typedArray.getColor(attr,Color.bLACK); break; case R.styleable.CustomtitleView_titleSize: mtitleSize = typedArray.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getresources().getDisplaymetrics())); break; case R.styleable.CustomtitleView_titleBACkground: mBACkground = typedArray.getColor(attr,Color.bLACK); break; case R.styleable.CustomtitleView_titleLenth: mLenth = typedArray.getInteger(attr,4); break; } } //回收 typedArray.recycle(); mPaint = new Paint(); randomText(); mPaint.setTextSize(mtitleSizE); //创建一个矩形 mBound = new Rect(); //第一个参数为要测量的文字,第二个参数为测量起始位置,第三个参数为测量的最后一个字符串的位置,第四个参数为rect对象 mPaint.getTextBounds(mtitleText.toString(),mtitleText.length(),mBound); }
obtainStyledAttributes的第二个属性为调用你刚在在attrs.xml文件里生命的declare-styleable标签的name
然后我们重写一下onMeasure@L_618_14@,通过getMeasuredLength@L_618_14@计算出宽和高
/** * 计算宽高 * * @param lenth widthMeasureSpec或heightMeasureSpec * @param isWidth true为计算宽度,false为计算高度 */ privatE int getMeasuredLength(int lenth,Boolean isWidth) { if (isWidth) { if (MeasureSpec.getMode(lenth) == MeasureSpec.EXACTLY) { //设置了精确尺寸,通过MeasureSpec.getSize()获得尺寸返回宽度 return MeasureSpec.getSize(lenth); } else { //设置了warp_content,则需要我们自己计算 /** * 首先给画笔设置文字大小 * 通过getTextBounds@L_618_14@获得绘制的Text的宽度 * 然后因为我们的自定义view只有一个text所以我们只需要getPaddingLeft()+getPaddingRight()+textwidth即可计算出显示出view所需要最小的宽度 * 一般计算宽度为getPaddingLeft()+getPaddingRight()+自己绘画的文字或者图片的宽度,因为计算的是所需宽度,假设我们绘制了图片+文字,那么就需要判断图片的宽度跟文字的宽度那个更大比如getPaddingLeft()+getPaddingRight()+Math.max(图片的宽度,文字的宽度)即得出所需宽度 */ if (MeasureSpec.getMode(lenth) == MeasureSpec.AT_MOST) { mPaint.setTextSize(mtitleSizE); mPaint.getTextBounds(mtitleText.toString(),mBound); float textwidth = mBound.width(); int desired = (int) (getPaddingLeft() + textwidth + getPaddingRight()); return Math.min(desired,MeasureSpec.getSize(lenth)); } } } else { if (MeasureSpec.getMode(lenth) == MeasureSpec.EXACTLY) { //用户设置了精确尺寸,通过MeasureSpec.getSize()获得尺寸返回高度 return MeasureSpec.getSize(lenth); } else { if (MeasureSpec.getMode(lenth) == MeasureSpec.AT_MOST) { //设置了warp_content,则需要我们自己计算 mPaint.setTextSize(mtitleSizE); mPaint.getTextBounds(mtitleText.toString(),mBound); float texthgeight = mBound.height(); int desired = (int) (getPaddingTop() + texthgeight + getPaddingBottom()); return Math.min(desired,MeasureSpec.getSize(lenth)); } } } return 0; }
@Override protected void onMeasure(int widthMeasureSpec,int heightMeasureSpeC) { setMeasuredDimension(getMeasuredLength(widthMeasureSpec,truE),getMeasuredLength(heightMeasureSpec,falsE)); }
系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。
所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMeasure@L_618_14@
重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
在这里有些初学者可能不理解getMode跟getSize的作用,首先getMode()用于判断宽高设置的模式,获得到之后即可判断,例如
//xx表示widthMeasureSpec或者heightMeasureSpec if(MeasureSpec.getMode(xX)==MeasureSpec.EXACTLY){ //进入这里则代表设置了match_parent或者将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="100dp",这样我们就可以直接通过MeasureSpec.getSize(xX)@L_618_14@获得宽或高 }else if(MeasureSpec.getMode(xX)==MeasureSpec.EXACTLY){ //进入这里代表设置了wrap_content,那么则需要我们自己计算宽或高 }else{ //进入这个则代表代表是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure@L_618_14@传入的模式 }
然后我们重写一下onDraw@L_618_14@、
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); padding_left = 0; mPaint.setColor(mBACkground); canvas.drawRect(0,getMeasuredWidth(),getMeasuredHeight(),mPaint); mPaint.setColor(mtitleColor); for (int i = 0; i < mtitleText.length(); i++) { randomTextStyle(mPaint); padding_left += mPaint.measureText(String.valueOf(mtitleText.charAt(i)))+10; canvas.drawText(String.valueOf(mtitleText.charAt(i)),padding_left,getHeight() / 2 + mBound.height() / 2,mPaint); } } private void randomTextStyle(Paint paint) { paint.setFakeBoldText(random.nextBoolean()); //true为粗体,false为非粗体 float skewX = random.nexTint(11) / 10; skewX = random.nextBoolean() ? skewX : -skewX; paint.setTextSkewX(skewX); //float类型参数,负数表示右斜,整数左斜 paint.setUnderlineText(true); //true为下划线,false为非下划线 paint.setStrikeThruText(false); //true为删除线,false为非删除线 }
这里绘制了多个字符串,并且使每个绘制的字符串都歪歪扭扭的,这样我们采用randomTextStyle()即可在每次绘制字符的时候设置每个字符都为不同的样式,在这里我们讲一下drawText的几个参数,第一个参数就是要绘制的文字内容,第二个参数为x轴,作用相当于左边距,第三个参数为Y轴,第四个参数为paint的实例,我的朋友具体讲了一下drawText的绘制坐标有兴趣的可以去看一下android canvas drawText()文字居中
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://@R_944_10906@mas.android.com/apk/res/android" xmlns:cq="http://@R_944_10906@mas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <chapter.com.rxjavachapter.CustomtitleView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:padding="10dp" cq@R_452_6964@BACkground="@android:color/black" cq@R_452_6964@Color="#ff0000" cq@R_452_6964@Lenth="4" cq@R_452_6964@Size="10sp" /> </RelativeLayout>
在根布局添加 xmlns:xx=”http://@R_944_10906@mas.android.com/apk/res-auto” 这里的xx可以是任何字母
然后用Xx去点我们在attr的name去设值,最后实现出的效果是这样
既然是验证码view,那么我们自然要开放出点击改变验证码内容的点击事件,在第三个构造@L_618_14@中添加click事件
@Override public void onClick(View v) { randomText(); posTinvalidate(); } /** * 获得随机的字符串 * * @return */ private void randomText() { mtitleText = new StringBuffer(); for (int i = 0; i < mLenth; i++) { mtitleText.append(data[(int) (Math.random() * data.length)]); } } /** * 获得到随机的值 * * @return */ public String getCode() { return mtitleText.toString(); } /** * 判断是否相同 * * @return */ public Boolean isEqual(String codE) { if (code != null) { return code.toUpperCase().equals(getCode().toUpperCase()) ? true : false; } else { return false; } }
这样就可以点击改变一次验证码内容了,并且我们开放出两个@L_618_14@作为判断验证码或得到验证码,我这只是简单的一个验证码,大家可以自己加入更多的东西。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
以上是大佬教程为你收集整理的Android自定义View实现验证码全部内容,希望文章能够帮你解决Android自定义View实现验证码所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。