Android仿支付宝支付验证按钮

支付宝之前更新的时候,支付验证时的按钮动画让我有种惊喜的感觉。
前几天突然心血来潮,打算自己做一个出来。
恩,下面是github地址和效果图。
其实真机上的动画速度会比较快 = =!

https://github.com/Linyuzai/Demo4RequestButton

request_button.gif

先介绍下用法吧

<com.linyuzai.requestbutton.RequestButton    
  android:id="@+id/end2"
  android:layout_width="match_parent"
  android:layout_height="50dp"
  android:layout_marginBottom="5dp"
  android:background="@drawable/bg" 
  icon:request_icon_size="2dp"
  icon:request_icon_spacing="25dp"
  icon:request_icon_style="tick_end_circle"
  icon:request_speed_multiplier="1.8"
  icon:text_color="@android:color/white"   
  icon:text_default="default"    
  icon:text_failure="failure"    
  icon:text_progress="progress"    
  icon:text_success="success" />

下面是所有的属性

<declare-styleable name="RequestButton">    
  <attr name="request_icon_spacing" format="dimension" />   
  <attr name="request_icon_color" format="color" />
  <attr name="request_icon_size" format="dimension" />  
  <attr name="request_icon_style" format="enum">
    <enum name="tick_start_circle" value="0" />   
    <enum name="tick_half_circle" value="1" />   
    <enum name="tick_end_circle" value="2" />   
  </attr> 
  <attr name="request_speed_multiplier" format="float" /> 
  <attr name="text_default" format="string" />  
  <attr name="text_progress" format="string" /> 
  <attr name="text_success" format="string" />    
  <attr name="text_failure" format="string" />    
  <attr name="text_color" format="color" />    
  <attr name="text_size" format="dimension" />    
  <attr name="text_width" format="dimension" />
</declare-styleable>

然后简单说明一下,嫌我啰嗦的请跳过

Attrs Introduction
request_icon_spacing icon和文本之间的间隔
默认0px
request_icon_color icon的颜色
默认白色
request_icon_size 画笔Paint的width
默认5px
request_icon_style 1.tick_start_circle
最后的画圈和打钩一起进行
2.tick_half_circle
最后的画圈画到一半开始打钩
3.tick_end_circle
最后的画圈画完之后再打钩
默认tick_start_circle
request_speed_multiplier 动画画圈和打钩的速度乘数
0.5-2.0,默认1.8
text_default 按钮默认文本
默认“default”
text_progress 请求时文本
默认“progress”
text_success 成功时文本
默认“success”
text_failure 失败时文本
默认“failure”
text_color 文本字体颜色
默认黑色
text_size 文本字体尺寸
默认20px
text_width 文本宽度
默认wrap_content
end2.setOnRequestCallback(new OnRequestCallback() {    
    @Override
    public boolean beforeRequest() {
        return true;
    }
    @Override    
    public void onRequest() {        
        Toast.makeText(MainActivity.this, "request", Toast.LENGTH_SHORT).show();    
    }    
    @Override    
    public void onFinish(boolean isSuccess) {
        Toast.makeText(MainActivity.this, "finish", Toast.LENGTH_SHORT).show();    
    }
});

不需要自己设置OnClickListener,beforeRequest()返回true开始请求,返回false不进行请求。在onRequest()里进行请求,成功或失败后手动调用requestSuccess()或者requestFailure(),等到icon画完就会回调到onFinish()

end2.requestSuccess();
end2.requestFailure();

接下来讲一下思路,暂时忽略速度的乘数
首先要画progress的时候,我定义了两个progress

public static final float CIRCLE_PROGRESS_MAX = 100f;
private float firstProgress;
private float secondProgress;

设置进度为100,假设进度为50时增量为1,那么加速度为0.02
第一条progress由快到慢,进度为firstProgress += 2-0.02*progress
第二条progress由慢到快,进度为secondProgress += 0.02*progress
等到画完一个圆再重置各个progress

float startAngle = 360f * secondProgress * speedMultiplier / CIRCLE_PROGRESS_MAX;
float sweepAngle = 360f * speedMultiplier * (firstProgress - secondProgress) / CIRCLE_PROGRESS_MAX;
canvas.drawArc(rectF, -90f + startAngle, sweepAngle, false, paint);
if (progress > CIRCLE_PROGRESS_MAX + 1f) {    
    progress = 0f;    
    firstProgress = 0f;    
    secondProgress = 0f;

第一部分算完成了
接下来是打钩之前的那个圆
这个更简单

float startCircleAngle = 360f * speedMultiplier * firstProgress / CIRCLE_PROGRESS_MAX;
canvas.drawArc(rectF, -90f, startCircleAngle, false, paint);

最后是画勾
我先定义了两个类

class Point {    
    float x;    
    float y;    
    public Point(float x, float y) {        
        this.x = x;        
        this.y = y;    
    }
}
class Line {    
    Point startPoint;    
    Point endPoint;    
    float k;    
    float b;    
    public Line(Point startPoint, Point endPoint) {        
        this.startPoint = startPoint;        
        this.endPoint = endPoint;        
        k = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x);    
        b = startPoint.y - k * startPoint.x;    
    }    
    public float getY(float x) {        
        return k * x + b;    
    }
}

接着就可以得到两条线段
勾的两条线段的长度比为1:2,斜率为-1和1
将整个控件分成10*10
第一条占0.15,就是一格半,第二条占0.3,就是三格,总共占0.45,四格半
然后微微的调整一下,在x,y轴上平移到本人还看得过去为止 = =!

firstLine = new Line(new Point(width * 0.28f, height * 0.53f), new Point(width * 0.43f, height * 0.68f));
secondLine = new Line(new Point(width * 0.43f, height * 0.68f), new Point(width * 0.73f, height * 0.38f));

我也将总共的进度设为100,那么第一条线段的进度为33.3,第二条为66.6
并且每次的增量为

lineProgressIncrease = width * 0.45f / 100f;

所以按照x求出y,得到终点,就可以画出所要的线段了,lineX及x坐标,并且之前说道忽略speedMultiplier,所以先用1代替

lineX = firstLine.startPoint.x;
lineProgress += speedMultiplier;
lineX += lineProgressIncrease * speedMultiplier;
canvas.drawLine(firstLine.startPoint.x, firstLine.startPoint.y, lineX, firstLine.getY(lineX), paint);

当lineProgress>33.3的时候

canvas.drawLine(firstLine.startPoint.x, firstLine.startPoint.y, firstLine.endPoint.x, firstLine.endPoint.y, paint);
canvas.drawLine(secondLine.startPoint.x, secondLine.startPoint.y, lineX, secondLine.getY(lineX), paint);

左边的icon画完了,接下来就简单了,把icon和TextView组合起来
你们肯定会想text要居中会用RelativeLayout,不过我用的是LinearLayout
好把提醒一下,weight属性


小弟初来乍到,希望各位大神能赏个脸
嗯,纯手打,发现写这玩意儿并不比敲代码简单
不过能够从头到尾review一遍,还是有帮助的
如果有什么bug或者更好的建议,随时欢迎

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,777评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,065评论 4 62
  • ——我问什么是爱情 是你 是我 是“我们” 是“曾经” ——我问什么才是对的人 愿意...
    切慕弥生阅读 413评论 0 2
  • 孩子的成功日记我已经写了60多天了,收获特别大。以前是写每天做的好的事情,前几天孩子突然和我说,妈妈我觉得成功日记...
    一个人的变化阅读 638评论 3 0
  • 每天早上,山上和山下的区别是,天晴的时候,山下有雾,在山上一眼望去,连绵千里,起伏不绝。一座座山峰在初升太阳...
    随意情怀阅读 168评论 0 3