丽1一10的数字怎样教代码是?

Quora:寻找最美数字
来自Quora问题:“哪个数字最美?为什么?”
Anne K. Halsall
我选数字6,因为它具有美感和数学、几何、生物甚至是精神上的意义。
它是第一个完全数,即它本身是所有它因子的总和(1+2+3)。
唯一的三个连贯正整数之和与积相同所得的数字。(1+2+3=1*2*3)
正六边形在自然界中以很多美丽的形式存在着,比如雪花和蜂窝。也是少数在平面上可以无限延展的图形。
6是碳的原子数,几乎地球上所有已知生命的生物学基础。
6是2维吻接数(Kissing Number ),这意味着它是单位圆相切的最大数。(吻接数:与一个n维球外切的等维球个数)
在许多方面,6在犹太教和基督教神话中有着重要意义:宇宙在六天中被创造出来,大卫之星有六个点,666则是经常与魔鬼相联系的神秘数字。
Ganesh Mohan
当然是108啦,居然没有提到。维基百科说得好:
在欧氏空间中,正五边形的每个内角为108度。
108是3的超阶乘 = 1^1*2?*3?= 108
108是斐波那契数
根据Φ函数,108可以被36整除。
108是哈沙德数。它在十进位制中可以被自身数字加起来的和:9整除。
108是自我数,它不会是任何一个正整数n 和n自身的数字所加起来的和。然而,它的前一位数107和109都不是自我数:107=94 + 9 + 4 = 103 + 1 + 0 + 3,109=95 + 9 + 5 = 104 + 1 + 0 + 4。
黄金分割率中, 2sin(108°/2)=?
宗教和艺术
单个数字1、0、8分别代表一、无和万物(无穷)
108代表宇宙的终极现实(看似矛盾的),类似归一、虚无和无限。
在印度教中:
印度教中也认为108是代表圆满的数字。印度教中的神祇都有108个名字。湿婆会跳108种舞蹈。而外士纳瓦传统中有108位温达文的牧牛姑娘。在咏唱这些名字的时候,通常拿着108颗珠子组成的念珠。这是非常神圣的,经常在宗教仪式期间举行。这种吟诵叫做复圣名(namajapa),相应的,所有名字要用念珠重复108遍。
从地球到太阳的距离除以太阳的直径和从地球到月球的距离除以月亮的直径大约等于108。据称,大吠檀多(印度教的主要哲学)之父知道这种关系,因此108在吠檀多礼拜是一个非常重要的数字。
许多东亚武术追根溯源都会回到佛教,具体来说,如佛教少林寺。因为他们与佛教的关系,在武术中108已经成为一个重要的象征性数字。
据马尔马阿迪(Marma Adi)和阿育吠陀(Ayurveda),人体有108处穴位,是灵与肉的交叉所,给予人以生命。
中国的武术学校和南印度武术学校都遵循108穴位的原则。
杨氏太极拳的动作形式有108式,咏春拳有108招。
美国职业棒球大联盟官方的棒球上有108个针脚。
在动漫系列,尸姬赫 (Shikabane Hime Aka )和尸姬玄(Shikabane Hime Kuro)中,尸姬必须杀死108名邪恶亡灵才能升入天堂。
的原子序数
索尼的视频游戏《龙骑士传说》中,有108物种,其中第108是毁灭之神。每108年,它的灵魂返回到世界来寻找宿主。
一副UNO牌有108张牌。
《水浒传》中,梁山好汉一百零八将。
《红楼梦》一共有一百零八回。
是美国电视连续剧《迷失》(Lost)中的重要号码,数列4,8,15,16,23,42的和。
现在来看一些很酷的插图:
2.分合设计(Concrete ,即'con'tinuous+dis'crete')
1和0是不连贯的,8 是流线状(sine-cosine)
索尼VAIO分合设计标志也是一个例子
“VA”类似于波浪,而“IO”则像是数字二进制代码
Aniket Yevankar
1.618(φ)是宇宙中最美丽的数。
这个数字也被称为Phi 、黄金数字或黄金比例,几乎整个宇宙都遵循这个神圣的数字。
连续分裂任何分数你都会得到1.618
相信我,理解这个数字你将探索到无限的可能性,它确实是一个神奇的数字。
Prithviraj Madhukar Billa
我认为最美的数字要属42。
42是“生命、宇宙以及任何事情的终极答案”,我猜大多数人从著名的《银河系漫游指南》中知道的。
首先,42是两个连续数字的产物(42 = 6 * 7)。
42是卡塔兰数(Catalan number)。
42的二进制是101010。(看起来很爽)
MATH(数学):字母表中,按所处顺序,M = 13,A= 1,T = 20,H = 8 。42 = 13 + 1 + 20 + 8。这是否意味着数学是生命、宇宙以及任何事情的终极答案”,或者这只是一个巧合
Aditya Tiwari
嗯,也许不是最漂亮的数字,但肯定是最有趣的数字之一。以下来自维基百科:
6174是著名的卡布列克常数/黑洞数(Kaprekar constant),由印度数学家卡布列克提出。
1. 取任意四个数字数,至少两个数字不同。(第一位可以是0)
2. 只要将数字重新排列,组合成最大值和最小值
3. 最大值减去最小值,得出数字。(差不够四位数时补零)
4. 重复步骤2
得到6174后,接着来:7641 – 1467 = 6174
例如:3524
5432 – 2345 = 3087
8730 – 0378 = 8352
8532 – 2358 = 6174
2111 – 1112 = 0999
9990 – 0999 = 8991 (不是 999 – 999 = 0)
9981 – 1899 = 8082
8820 – 0288 = 8532
8532 – 2358 = 6174.
上述过程,称为Kaprekar routine,七次以内就会出现6174。
三位数中495也是相同的效果。
Souktik Roy
说实话,我不能做出选择。
因为每个数字都有其独特的美。
(涨了数学知识==)
id="cos_support-3]
id="cos_unsupport-]
19:18:58 :
id="cos_support-]
id="cos_unsupport-]
19:22:01 :
id="cos_support-]
id="cos_unsupport-]
19:20:07 :
id="cos_support-]
id="cos_unsupport-]
19:21:21 :
id="cos_support-]
id="cos_unsupport-]
金三胖胖三斤
19:57:15 :
id="cos_support-]
id="cos_unsupport-]
幕后煮屎者
19:24:12 :
id="cos_support-]
id="cos_unsupport-]
勇敢的骚年
19:20:35 :
id="cos_support-]
id="cos_unsupport-]
吐啊吐地吐了
19:34:57 :
id="cos_support-]
id="cos_unsupport-]
19:50:34 :
id="cos_support-]
id="cos_unsupport-]特殊符号数字代码大全_百度知道
特殊符号数字代码大全
我有更好的答案
貌似百度搜堆参考资料:
是倒萨大师的
搜狗输入法设置里挺全的
在智能ABC下v+4就可以了
明天写给你!
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁Android自定义view制作绚丽的验证码
作者:ydxlt
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Android自定义view制作绚丽的验证码的相关资料,需要的朋友可以参考下
废话不多说了,先给大家展示下自定义view效果图,如果大家觉得还不错的话,请继续往下阅读。
怎么样,这种验证码是不是很常见呢,下面我们就自己动手实现这种效果,自己动手,丰衣足食,哈哈~
一、 自定义view的步骤
自定义view一直被认为android进阶通向高手的必经之路,其实自定义view好简单,自定义view真正难的是如何绘制出高难度的图形,这需要有好的数学功底(后悔没有好好学数学了~),因为绘制图形经常要计算坐标点及类似的几何变换等等。自定义view通常只需要以下几个步骤:
写一个类继承View类;
重新View的构造方法;
测量View的大小,也就是重写onMeasure()方法;
重新onDraw()方法。
其中第三步不是必须的,只有当系统无法确定自定义的view的大小的时候需要我们自己重写onMeasure()方法来完成自定义view大小的测量,因为如果用户(程序员)在使用我们的自定义view的时候没有指定其精确大小(宽度或高度),如:布局文件中layout_width或layout_heigth属性值为wrap_content而不是match_parent或某个精确的值,那么系统就不知道我们自定义view在onDraw()中绘制的图形的大小,所以通常要让我们自定义view支持wrap_content那么我们就必须重写onMeasure方法来告诉系统我们要绘制的view的大小(宽度和高度)。
还有,如果我们自定义view需要一些特殊的属性,那么我们还需要自定义属性,这篇文章将会涉及到自定义属性和上面的四个步骤的内容。
二、 自定义view的实现
要实现这种验证码控件,我们需要先分析一下它要怎么实现。通过看上面的效果图,我们可以知道要实现这种效果,首先需要在绘制验证码字符串,即图中的文本部分,然后绘制一些干扰点,再就是绘制干扰线了,分析完毕。下面我们根据分析结果一步步实现这种效果。
1. 继承View,重写构造方法
写一个类继承View,然后重新它的构造方法
* Created by lt on .
public class ValidationCode extends View{
* 在java代码中创建view的时候调用,即new
* @param context
public ValidationCode(Context context) {
this(context,null);
* 在xml布局文件中使用view但没有指定style的时候调用
* @param context
* @param attrs
public ValidationCode(Context context, AttributeSet attrs) {
this(context, attrs, 0);
* 在xml布局文件中使用view并指定style的时候调用
* @param context
* @param attrs
* @param defStyleAttr
public ValidationCode(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 做一些初始化工作
View有三个构造方法,一般的做法都是让一个参数和两个参数的构造方法调用三个构造参数的方法,这三个构造方法的调用情况看方法上面的注释。在这个构造方法里面我们先做一些初始化随机验证码字符串,画笔等工作:
* 初始化一些数据
private void init() {
// 生成随机数字和字母组合
mCodeString = getCharAndNumr(mCodeCount);
// 初始化文字画笔
mTextPaint = new Paint();
mTextPaint.setStrokeWidth(3); // 画笔大小为3
mTextPaint.setTextSize(mTextSize); // 设置文字大小
// 初始化干扰点画笔
mPointPaint = new Paint();
mPointPaint.setStrokeWidth(6);
mPointPaint.setStrokeCap(Paint.Cap.ROUND); // 设置断点处为圆形
// 初始化干扰线画笔
mPathPaint = new Paint();
mPathPaint.setStrokeWidth(5);
mPathPaint.setColor(Color.GRAY);
mPathPaint.setStyle(Paint.Style.STROKE); // 设置画笔为空心
mPathPaint.setStrokeCap(Paint.Cap.ROUND); // 设置断点处为圆形
// 取得验证码字符串显示的宽度值
mTextWidth = mTextPaint.measureText(mCodeString);
到这里,我们就完成了自定义View步骤中的前面的两小步了,接下来就是完成第三步,即重写onMeasure()进行我们自定义view大小(宽高)的测量了:
2. 重写onMeasure(),完成View大小的测量
* 要像layout_width和layout_height属性支持wrap_content就必须重新这个方法
* @param widthMeasureSpec
* @param heightMeasureSpec
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 分别测量控件的宽度和高度,基本为模板方法
int measureWidth = measureWidth(widthMeasureSpec);
int measureHeight = measureHeight(heightMeasureSpec);
// 其实这个方法最终会调用setMeasuredDimension(int measureWidth,int measureHeight);
// 将测量出来的宽高设置进去完成测量
setMeasuredDimension(measureWidth, measureHeight);
测量宽度的方法:
* 测量宽度
* @param widthMeasureSpec
private int measureWidth(int widthMeasureSpec) {
int result = (int) (mTextWidth*1.8f);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
if(widthMode == MeasureSpec.EXACTLY){
// 精确测量模式,即布局文件中layout_width或layout_height一般为精确的值或match_parent
result = widthS // 既然是精确模式,那么直接返回测量的宽度即可
if(widthMode == MeasureSpec.AT_MOST) {
// 最大值模式,即布局文件中layout_width或layout_height一般为wrap_content
result = Math.min(result,widthSize);
测量高度的方法:
* 测量高度
* @param heightMeasureSpec
private int measureHeight(int heightMeasureSpec) {
int result = (int) (mTextWidth/1.6f);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(heightMode == MeasureSpec.EXACTLY){
// 精确测量模式,即布局文件中layout_width或layout_height一般为精确的值或match_parent
result = heightS // 既然是精确模式,那么直接返回测量的宽度即可
if(heightMode == MeasureSpec.AT_MOST) {
// 最大值模式,即布局文件中layout_width或layout_height一般为wrap_content
result = Math.min(result,heightSize);
说明:其实onMeasure()方法最终会调用setMeasuredDimension(int measureWidth,int measureHeight);将测量出来的宽高设置进去完成测量,而我们要做的就是测量得到宽度和高度的值,测量宽度和高度的方法最重要的就是得到当用户(程序员)没有给我们的控件指定精确的值(具体数值或match_parent)时合适的宽度和高度,所以,以上测量宽度和高度的方法基本上是一个模板方法,要做的就是得到result的一个合适的值,这里我们无需关注给result的那个值,因为这个值根据控件算出来的一个合适的值(也许不是很合适)。
完成了控件的测量,那么接下来我们还要完成控件的绘制这一大步,也就是自定义view的核心的一步重写onDraw()方法绘制图形。
3. 重写onDraw(),绘制图形
根据我们上面的分析,我们需要绘制验证码文本字符串,干扰点,干扰线。由于干扰点和干扰线需要坐标和路径来绘制, 所以在绘制之前先做一些初始化随机干扰点坐标和干扰线路径:
private void initData() {
// 获取控件的宽和高,此时已经测量完成
mHeight = getHeight();
mWidth = getWidth();
mPoints.clear();
// 生成干扰点坐标
for(int i=0;i&150;i++){
PointF pointF = new PointF(mRandom.nextInt(mWidth)+10,mRandom.nextInt(mHeight)+10);
mPoints.add(pointF);
mPaths.clear();
// 生成干扰线坐标
for(int i=0;i&2;i++){
Path path = new Path();
int startX = mRandom.nextInt(mWidth/3)+10;
int startY = mRandom.nextInt(mHeight/3)+10;
int endX = mRandom.nextInt(mWidth/2)+mWidth/2-10;
int endY = mRandom.nextInt(mHeight/2)+mHeight/2-10;
path.moveTo(startX,startY);
path.quadTo(Math.abs(endX-startX)/2,Math.abs(endY-startY)/2,endX,endY);
mPaths.add(path);
有了这些数据之后,我们可以开始绘制图形了。
(1)绘制验证码文本字符串
由于验证码文本字符串是随机生成的,所以我们需要利用代码来随机生成这种随机验证码:
* java生成随机数字和字母组合
* @param length[生成随机数的长度]
public static String getCharAndNumr(int length) {
String val = "";
Random random = new Random();
for (int i = 0; i & i++) {
// 输出字母还是数字
String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
if ("char".equalsIgnoreCase(charOrNum)) {
// 取得大写字母还是小写字母
int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
val += (char) (choice + random.nextInt(26));
} else if ("num".equalsIgnoreCase(charOrNum)) { // 数字
val += String.valueOf(random.nextInt(10));
这种代码是java基础,相信大家都看得懂,看不懂也没关系,这种代码网上随便一搜就有,其实我也是直接从网上搜的,嘿嘿~。
android的2D图形api canvas提供了drawXXX()方法来完成各种图形的绘制,其中就有drawText()方法来绘制文本,同时还有drawPosText()在给定的坐标点上绘制文本,drawTextOnPath()在给定途径上绘制图形。仔细观察上面的效果图,发现文本有的不是水平的,即有的被倾斜了,这就可以给我们的验证码提升一定的识别难度,要实现文字倾斜效果,我们可以通过drawTextOnPath()在给定路径绘制文本达到倾斜效果,然而这种方法实现比较困难(坐标点和路径难以计算),所以,我们可以通过canvas提供的位置变换方法rorate()结合drawText()实现文本倾斜效果。
int length = mCodeString.length();
float charLength = mTextWidth/
for(int i=1;i&=i++){
int offsetDegree = mRandom.nextInt(15);
// 这里只会产生0和1,如果是1那么正旋转正角度,否则旋转负角度
offsetDegree = mRandom.nextInt(2) == 1?offsetDegree:-offsetD
canvas.save();
canvas.rotate(offsetDegree, mWidth / 2, mHeight / 2);
// 给画笔设置随机颜色,+20是为了去除一些边界值
mTextPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);canvas.drawText(String.valueOf(mCodeString.charAt(i - 1)), (i-1) * charLength * 1.6f+30, mHeight * 2 / 3f, mTextPaint);
canvas.restore();
这段代码通过for循环分别绘制验证码字符串中的每个字符,每绘制一个字符都将画布旋转一个随机的正负角度,然后通过drawText()方法绘制字符,每个字符的绘制起点坐标根据字符的长度和位置不同而不同,这个自己计算,这里也许也不是很合适。要注意的是,每次对画布canvas进行位置变换的时候都要先调用canvas.save()方法保存好之前绘制的图形,绘制结束后调用canvas.restore()恢复画布的位置,以便下次绘制图形的时候不会由于之前画布的位置变化而受影响。
(2)绘制干扰点
// 产生干扰效果1 -- 干扰点
for(PointF pointF : mPoints){
mPointPaint.setARGB(255,mRandom.nextInt(200)+20,mRandom.nextInt(200)+20,mRandom.nextInt(200)+20);
canvas.drawPoint(pointF.x,pointF.y,mPointPaint);
给干扰点画笔设置随机颜色,然后根据随机产生的点的坐标利用canvas.drawPoint()绘制点。
(3)绘制干扰线
// 产生干扰效果2 -- 干扰线
for(Path path : mPaths){
mPathPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);
canvas.drawPath(path, mPathPaint);
给干扰线画笔设置随机颜色,然后根据随机产生路径利用canvas.drawPath()绘制贝塞尔曲线,从而绘制出干扰线。
4. 重写onTouchEvent,定制View事件
这里做这一步是为了实现当我们点击我们的自定义View的时候,完成一些操作,即定制View事件。这里,我们需要当用户点击验证码控件的时候,改变验证码的文本字符串。
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
// 重新生成随机数字和字母组合
mCodeString = getCharAndNumr(mCodeCount);
invalidate();
return super.onTouchEvent(event);
OK,到这里我们的这个自定义View就基本完成了,可能大家会问,这个自定义View是不是扩展性太差了,定制性太低了,说好的自定义属性呢?跑哪里去了。不要急,下面我们就来自定义我们自己View的属性,自定义属性。
5. 自定义属性,提高自定义View的可定制性
(1)在资源文件attrs.xml文件中定义我们的属性(集)
&?xml version="1.0" encoding="utf-8"?&
&resources&
&declare-styleable name="IndentifyingCode"&
&attr name="codeCount" format="integer|reference"&&/attr&
&attr name="textSize" format="dimension"&&/attr&
&/declare-styleable&
&/resources&
在attrs.xml文件中的attr节点中定义我们的属性,定义属性需要name属性表示我们的属性值,同时需要format属性表示属性值的格式,其格式有很多种,如果属性值可以使多种格式,那么格式间用”|”分开;
declare-styleable节点用来定义我们自定义属性集,其name属性指定了该属性集的名称,可以任意,但一般为自定义控件的名称;
如果属性已经定义了(如layout_width),那么可以直接引用该属性,不要指定格式了。
(2)在布局文件中引用自定义属性,注意需要引入命名空间
&RelativeLayout xmlns:android="/apk/res/android" xmlns:tools="/tools" xmlns:lt="/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"&
&com.lt.identifyingcode.ValidationCode
android:id="@+id/validationCode"
android:layout_width="wrap_content"
android:layout_centerInParent="true"
lt:textSize="25sp"
android:background="@android:color/darker_gray"
android:layout_height="wrap_content"/&
&/RelativeLayout&
引入命名空间在现在只需要添加xmlns:lt="/apk/res-auto"即可(lt换成你自己的命名空间名称),而在以前引入命名空间方式为xmlns:custom="/apk/res/com.example.customview01",res后面的包路径指的是项目的package`
(3)在构造方法中获取自定义属性的值
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.IndentifyingCode);
mCodeCount = typedArray.getInteger(R.styleable.IndentifyingCode_codeCount, 5); // 获取布局中验证码位数属性值,默认为5个
// 获取布局中验证码文字的大小,默认为20sp
mTextSize = typedArray.getDimension(R.styleable.IndentifyingCode_textSize, typedArray.getDimensionPixelSize(R.styleable.IndentifyingCode_textSize, (int) TypedValue.PLEX_UNIT_SP, 20, getResources().getDisplayMetrics())));
// 一个好的习惯是用完资源要记得回收,就想打开数据库和IO流用完后要记得关闭一样
typedArray.recycle();
OK,自定义属性也完成了,值也获取到了,那么我们只需要将定制的属性值在我们onDraw()绘制的时候使用到就行了,自定义属性就是这么简单~,看到这里,也许有点混乱了,看一下完整代码整理一下。
package com.lt.
import android.content.C
import android.content.res.TypedA
import android.graphics.C
import android.graphics.C
import android.graphics.P
import android.graphics.P
import android.graphics.PointF;
import android.util.AttributeS
import android.util.TypedV
import android.view.MotionE
import android.view.V
import java.util.ArrayL
import java.util.R
* Created by lt on .
public class ValidationCode extends View{
* 控件的宽度
private int mW
* 控件的高度
private int mH
* 验证码文本画笔
private Paint mTextP // 文本画笔
* 干扰点坐标的集合
private ArrayList&PointF& mPoints = new ArrayList&PointF&();
private Random mRandom = new Random();;
* 干扰点画笔
private Paint mPointP
* 绘制贝塞尔曲线的路径集合
private ArrayList&Path& mPaths = new ArrayList&Path&();
* 干扰线画笔
private Paint mPathP
* 验证码字符串
private String mCodeS
* 验证码的位数
private int mCodeC
* 验证码字符的大小
private float mTextS
* 验证码字符串的显示宽度
private float mTextW
* 在java代码中创建view的时候调用,即new
* @param context
public ValidationCode(Context context) {
this(context,null);
* 在xml布局文件中使用view但没有指定style的时候调用
* @param context
* @param attrs
public ValidationCode(Context context, AttributeSet attrs) {
this(context, attrs, 0);
* 在xml布局文件中使用view并指定style的时候调用
* @param context
* @param attrs
* @param defStyleAttr
public ValidationCode(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getAttrValues(context, attrs);
// 做一些初始化工作
* 获取布局文件中的值
* @param context
private void getAttrValues(Context context,AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.IndentifyingCode);
mCodeCount = typedArray.getInteger(R.styleable.IndentifyingCode_codeCount, 5); // 获取布局中验证码位数属性值,默认为5个
// 获取布局中验证码文字的大小,默认为20sp
mTextSize = typedArray.getDimension(R.styleable.IndentifyingCode_textSize, typedArray.getDimensionPixelSize(R.styleable.IndentifyingCode_textSize, (int) TypedValue.PLEX_UNIT_SP, 20, getResources().getDisplayMetrics())));
// 一个好的习惯是用完资源要记得回收,就想打开数据库和IO流用完后要记得关闭一样
typedArray.recycle();
* 要像layout_width和layout_height属性支持wrap_content就必须重新这个方法
* @param widthMeasureSpec
* @param heightMeasureSpec
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 分别测量控件的宽度和高度,基本为模板方法
int measureWidth = measureWidth(widthMeasureSpec);
int measureHeight = measureHeight(heightMeasureSpec);
// 其实这个方法最终会调用setMeasuredDimension(int measureWidth,int measureHeight);
// 将测量出来的宽高设置进去完成测量
setMeasuredDimension(measureWidth, measureHeight);
protected void onDraw(Canvas canvas) {
// 初始化数据
initData();
int length = mCodeString.length();
float charLength = mTextWidth/
for(int i=1;i&=i++){
int offsetDegree = mRandom.nextInt(15);
// 这里只会产生0和1,如果是1那么正旋转正角度,否则旋转负角度
offsetDegree = mRandom.nextInt(2) == 1?offsetDegree:-offsetD
canvas.save();
canvas.rotate(offsetDegree, mWidth / 2, mHeight / 2);
// 给画笔设置随机颜色
mTextPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);
canvas.drawText(String.valueOf(mCodeString.charAt(i - 1)), (i-1) * charLength * 1.6f+30, mHeight * 2 / 3f, mTextPaint);
canvas.restore();
// 产生干扰效果1 -- 干扰点
for(PointF pointF : mPoints){
mPointPaint.setARGB(255,mRandom.nextInt(200)+20,mRandom.nextInt(200)+20,mRandom.nextInt(200)+20);
canvas.drawPoint(pointF.x,pointF.y,mPointPaint);
// 产生干扰效果2 -- 干扰线
for(Path path : mPaths){
mPathPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);
canvas.drawPath(path, mPathPaint);
private void initData() {
// 获取控件的宽和高,此时已经测量完成
mHeight = getHeight();
mWidth = getWidth();
mPoints.clear();
// 生成干扰点坐标
for(int i=0;i&150;i++){
PointF pointF = new PointF(mRandom.nextInt(mWidth)+10,mRandom.nextInt(mHeight)+10);
mPoints.add(pointF);
mPaths.clear();
// 生成干扰线坐标
for(int i=0;i&2;i++){
Path path = new Path();
int startX = mRandom.nextInt(mWidth/3)+10;
int startY = mRandom.nextInt(mHeight/3)+10;
int endX = mRandom.nextInt(mWidth/2)+mWidth/2-10;
int endY = mRandom.nextInt(mHeight/2)+mHeight/2-10;
path.moveTo(startX,startY);
path.quadTo(Math.abs(endX-startX)/2,Math.abs(endY-startY)/2,endX,endY);
mPaths.add(path);
* 初始化一些数据
private void init() {
// 生成随机数字和字母组合
mCodeString = getCharAndNumr(mCodeCount);
// 初始化文字画笔
mTextPaint = new Paint();
mTextPaint.setStrokeWidth(3); // 画笔大小为3
mTextPaint.setTextSize(mTextSize); // 设置文字大小
// 初始化干扰点画笔
mPointPaint = new Paint();
mPointPaint.setStrokeWidth(6);
mPointPaint.setStrokeCap(Paint.Cap.ROUND); // 设置断点处为圆形
// 初始化干扰线画笔
mPathPaint = new Paint();
mPathPaint.setStrokeWidth(5);
mPathPaint.setColor(Color.GRAY);
mPathPaint.setStyle(Paint.Style.STROKE); // 设置画笔为空心
mPathPaint.setStrokeCap(Paint.Cap.ROUND); // 设置断点处为圆形
// 取得验证码字符串显示的宽度值
mTextWidth = mTextPaint.measureText(mCodeString);
* java生成随机数字和字母组合
* @param length[生成随机数的长度]
public static String getCharAndNumr(int length) {
String val = "";
Random random = new Random();
for (int i = 0; i & i++) {
// 输出字母还是数字
String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
if ("char".equalsIgnoreCase(charOrNum)) {
// 取得大写字母还是小写字母
int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
val += (char) (choice + random.nextInt(26));
} else if ("num".equalsIgnoreCase(charOrNum)) { // 数字
val += String.valueOf(random.nextInt(10));
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
// 重新生成随机数字和字母组合
mCodeString = getCharAndNumr(mCodeCount);
invalidate();
return super.onTouchEvent(event);
* 测量宽度
* @param widthMeasureSpec
private int measureWidth(int widthMeasureSpec) {
int result = (int) (mTextWidth*1.8f);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
if(widthMode == MeasureSpec.EXACTLY){
// 精确测量模式,即布局文件中layout_width或layout_height一般为精确的值或match_parent
result = widthS // 既然是精确模式,那么直接返回测量的宽度即可
if(widthMode == MeasureSpec.AT_MOST) {
// 最大值模式,即布局文件中layout_width或layout_height一般为wrap_content
result = Math.min(result,widthSize);
* 测量高度
* @param heightMeasureSpec
private int measureHeight(int heightMeasureSpec) {
int result = (int) (mTextWidth/1.6f);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(heightMode == MeasureSpec.EXACTLY){
// 精确测量模式,即布局文件中layout_width或layout_height一般为精确的值或match_parent
result = heightS // 既然是精确模式,那么直接返回测量的宽度即可
if(heightMode == MeasureSpec.AT_MOST) {
// 最大值模式,即布局文件中layout_width或layout_height一般为wrap_content
result = Math.min(result,heightSize);
* 获取验证码字符串,进行匹配的时候只需要字符串比较即可(具体比较规则自己决定)
* @return 验证码字符串
public String getCodeString() {
return mCodeS
总结:这里与其说自定义View到不如说是绘制图形,关键在于坐标点的计算,这里在计算坐标上也许不太好,以上是给大家分享Android自定义view制作绚丽的验证码,希望对大家有所帮助!大家有什么好的思路或者建议希望可以留言告诉我,感激不尽~。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 代码 的文章

 

随机推荐