android view flag,Android自定义View实现验证码

首先我们定义一个declare-styleable标签declare-styleable标签的作用是给自定义控件添加自定义属性用的例如这样

(我们定义了文字的颜色,大小,长度,跟背景的颜色)

Android提供了自定义属性的方法,其中的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:

这个参数作用为:位或运算

一个自定义View的步骤为

1、自定义View的属性

2、在View的构造方法中获得我们自定义的属性

3、重写onMeasure

4、重写onDraw

有的时候onMeasure方法是不用重写的例如系统自带组件等

然后我们定义一下需要的属性

//文本

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, attrs, 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(), 0, mTitleText.length(), mBound);

}

obtainStyledAttributes的第二个属性为调用你刚在在attrs.xml文件里生命的declare-styleable标签的name

然后我们重写一下onMeasure方法,通过getMeasuredLength方法计算出宽和高

/**

* 计算宽高

*

* @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方法获得绘制的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(), 0, mTitleText.length(), 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(), 0, mTitleText.length(), mBound);

float texthgeight = mBound.height();

int desired = (int) (getPaddingTop() + texthgeight + getPaddingBottom());

return Math.min(desired,MeasureSpec.getSize(lenth));

}

}

}

return 0;

}

然后在onMeasure方法里调用

@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方法

重写之前先了解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)方法获得宽或高

}else if(MeasureSpec.getMode(xx)==MeasureSpec.EXACTLY){

//进入这里代表设置了wrap_content,那么则需要我们自己计算宽或高

}else{

//进入这个则代表代表是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式

}

然后我们重写一下onDraw方法、

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

padding_left = 0;

mPaint.setColor(mBackground);

canvas.drawRect(0, 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()文字居中

最后我们在布局文件中引用我们的自定义view

xmlns:cq="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="horizontal">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:padding="10dp"

cq:titleBackground="@android:color/black"

cq:titleColor="#ff0000"

cq:titleLenth="4"

cq:titleSize="10sp" />

在根布局添加 xmlns:xx=”http://schemas.android.com/apk/res-auto” 这里的xx可以是任何字母

然后用xx去点我们在attr的name去设值,最后实现出的效果是这样

744e89fa6bc8d683817bc28359b91460.png

既然是验证码view,那么我们自然要开放出点击改变验证码内容的点击事件,在第三个构造方法中添加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;

}

}

这样就可以点击改变一次验证码内容了,并且我们开放出两个方法作为判断验证码或得到验证码,我这只是简单的一个验证码,大家可以自己加入更多的东西。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值