支付宝之前更新的时候,支付验证时的按钮动画让我有种惊喜的感觉。
前几天突然心血来潮,打算自己做一个出来。
恩,下面是github地址和效果图。
其实真机上的动画速度会比较快 = =!
https://github.com/Linyuzai/Demo4RequestButton
先介绍下用法吧
<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或者更好的建议,随时欢迎