Android波纹扩散效果之仿支付宝咻一咻功能实现波纹扩散特效

时间:2021-12-29 06:21:04

今年春节晚会没看尽兴,被支付宝集福给添了一段插曲,朋友们都在那数定时间段不停的咻一咻,哇,我咻到一个敬业福,不可能的,哈哈。那么咻一咻功能基于程序代码是怎么实现的呢?下面服务器之家小编给大家分享本教程帮助大家学习android波纹扩散效果之仿支付宝咻一咻功能实现波纹扩散特效,具体内容如下所示:

先来看看这个效果

Android波纹扩散效果之仿支付宝咻一咻功能实现波纹扩散特效

这是我的在only上添加的效果,说实话,only现在都还只是半成品,台面都上不了,怪自己技术不行,也太懒了
ps:这个view也是我模仿了人家的效果,参考了人家的思路写的,不是纯手撸,罪过罪过,网上应该也能找到很多这样的效果,我只是加入了一些自己的需求在里面

我么新建一个工程——whew

roundimageview

这个之前讲过网上 的粒子,把头像变成圆形的,这里就不多说了,直接撸代码吧!

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package com.lgl.whew;
 
/**
* 圆形头像
* created by lgl on 2016/1/12.
*/
import android.content.context;
import android.content.res.typedarray;
import android.graphics.bitmap;
import android.graphics.canvas;
import android.graphics.paint;
import android.graphics.porterduff;
import android.graphics.porterduffxfermode;
import android.graphics.rect;
import android.graphics.drawable.bitmapdrawable;
import android.graphics.drawable.drawable;
import android.graphics.drawable.ninepatchdrawable;
import android.util.attributeset;
import android.widget.imageview;
/**
* 圆形imageview,可设置最多两个宽度不同且颜色不同的圆形边框。
*
* 设置颜色在xml布局文件中由自定义属性配置参数指定
*/
public class roundimageview extends imageview {
private int mborderthickness = 0;
private context mcontext;
private int defaultcolor = 0xffffffff;
// 如果只有其中一个有值,则只画一个圆形边框
private int mborderoutsidecolor = 0;
private int mborderinsidecolor = 0;
// 控件默认长、宽
private int defaultwidth = 0;
private int defaultheight = 0;
public roundimageview(context context) {
super(context);
mcontext = context;
}
public roundimageview(context context, attributeset attrs) {
super(context, attrs);
mcontext = context;
setcustomattributes(attrs);
}
public roundimageview(context context, attributeset attrs, int defstyle) {
super(context, attrs, defstyle);
mcontext = context;
setcustomattributes(attrs);
}
private void setcustomattributes(attributeset attrs) {
typedarray a = mcontext.obtainstyledattributes(attrs,
r.styleable.roundedimageview);
mborderthickness = a.getdimensionpixelsize(
r.styleable.roundedimageview_border_thickness, 0);
mborderoutsidecolor = a
.getcolor(r.styleable.roundedimageview_border_outside_color,
defaultcolor);
mborderinsidecolor = a.getcolor(
r.styleable.roundedimageview_border_inside_color, defaultcolor);
}
@override
protected void ondraw(canvas canvas) {
drawable drawable = getdrawable();
if (drawable == null) {
return;
}
if (getwidth() == 0 || getheight() == 0) {
return;
}
this.measure(0, 0);
if (drawable.getclass() == ninepatchdrawable.class)
return;
bitmap b = ((bitmapdrawable) drawable).getbitmap();
bitmap bitmap = b.copy(bitmap.config.argb_8888, true);
if (defaultwidth == 0) {
defaultwidth = getwidth();
}
if (defaultheight == 0) {
defaultheight = getheight();
}
int radius = 0;
if (mborderinsidecolor != defaultcolor
&& mborderoutsidecolor != defaultcolor) {// 定义画两个边框,分别为外圆边框和内圆边框
radius = (defaultwidth < defaultheight ? defaultwidth
: defaultheight) / 2 - 2 * mborderthickness;
// 画内圆
drawcircleborder(canvas, radius + mborderthickness / 2,
mborderinsidecolor);
// 画外圆
drawcircleborder(canvas, radius + mborderthickness
+ mborderthickness / 2, mborderoutsidecolor);
} else if (mborderinsidecolor != defaultcolor
&& mborderoutsidecolor == defaultcolor) {// 定义画一个边框
radius = (defaultwidth < defaultheight ? defaultwidth
: defaultheight) / 2 - mborderthickness;
drawcircleborder(canvas, radius + mborderthickness / 2,
mborderinsidecolor);
} else if (mborderinsidecolor == defaultcolor
&& mborderoutsidecolor != defaultcolor) {// 定义画一个边框
radius = (defaultwidth < defaultheight ? defaultwidth
: defaultheight) / 2 - mborderthickness;
drawcircleborder(canvas, radius + mborderthickness / 2,
mborderoutsidecolor);
} else {// 没有边框
radius = (defaultwidth < defaultheight ? defaultwidth
: defaultheight) / 2;
}
bitmap roundbitmap = getcroppedroundbitmap(bitmap, radius);
canvas.drawbitmap(roundbitmap, defaultwidth / 2 - radius, defaultheight
/ 2 - radius, null);
}
/**
* 获取裁剪后的圆形图片
*/
public bitmap getcroppedroundbitmap(bitmap bmp, int radius) {
bitmap scaledsrcbmp;
int diameter = radius * 2;
// 为了防止宽高不相等,造成圆形图片变形,因此截取长方形中处于中间位置最大的正方形图片
int bmpwidth = bmp.getwidth();
int bmpheight = bmp.getheight();
int squarewidth = 0, squareheight = 0;
int x = 0, y = 0;
bitmap squarebitmap;
if (bmpheight > bmpwidth) {// 高大于宽
squarewidth = squareheight = bmpwidth;
x = 0;
y = (bmpheight - bmpwidth) / 2;
// 截取正方形图片
squarebitmap = bitmap.createbitmap(bmp, x, y, squarewidth,
squareheight);
} else if (bmpheight < bmpwidth) {// 宽大于高
squarewidth = squareheight = bmpheight;
x = (bmpwidth - bmpheight) / 2;
y = 0;
squarebitmap = bitmap.createbitmap(bmp, x, y, squarewidth,
squareheight);
} else {
squarebitmap = bmp;
}
if (squarebitmap.getwidth() != diameter
|| squarebitmap.getheight() != diameter) {
scaledsrcbmp = bitmap.createscaledbitmap(squarebitmap, diameter,
diameter, true);
} else {
scaledsrcbmp = squarebitmap;
}
bitmap output = bitmap.createbitmap(scaledsrcbmp.getwidth(),
scaledsrcbmp.getheight(),
bitmap.config.argb_8888);
canvas canvas = new canvas(output);
paint paint = new paint();
rect rect = new rect(0, 0, scaledsrcbmp.getwidth(),
scaledsrcbmp.getheight());
paint.setantialias(true);
paint.setfilterbitmap(true);
paint.setdither(true);
canvas.drawargb(0, 0, 0, 0);
canvas.drawcircle(scaledsrcbmp.getwidth() / 2,
scaledsrcbmp.getheight() / 2,
scaledsrcbmp.getwidth() / 2,
paint);
paint.setxfermode(new porterduffxfermode(porterduff.mode.src_in));
canvas.drawbitmap(scaledsrcbmp, rect, rect, paint);
bmp = null;
squarebitmap = null;
scaledsrcbmp = null;
return output;
}
/**
* 边缘画圆
*/
private void drawcircleborder(canvas canvas, int radius, int color) {
paint paint = new paint();
/* 去锯齿 */
paint.setantialias(true);
paint.setfilterbitmap(true);
paint.setdither(true);
paint.setcolor(color);
/* 设置paint的 style 为stroke:空心 */
paint.setstyle(paint.style.stroke);
/* 设置paint的外框宽度 */
paint.setstrokewidth(mborderthickness);
canvas.drawcircle(defaultwidth / 2, defaultheight / 2, radius, paint);
}
}

这里值得注意的是,要使用这个必须自定义一些属性,我们在values下新建一个attr.xml

?
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="roundedimageview">
<attr name="border_thickness" format="dimension" />
<attr name="border_inside_color" format="color" />
<attr name="border_outside_color" format="color"></attr>
</declare-styleable>
</resources>

然后在xml文件中引入命名空间

?
1
xmlns:imagecontrol=http://schemas.android.com/apk/res-auto

我们直接看layout_mian.xml吧

layout_mian.xml

就一些布局咯

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:imagecontrol="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<relativelayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.lgl.whew.whewview
android:id="@+id/wv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.lgl.whew.roundimageview
android:id="@+id/my_photo"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerinparent="true"
android:src="@drawable/myphoto"
imagecontrol:border_inside_color="#bc0978"
imagecontrol:border_outside_color="#ba3456"
imagecontrol:border_thickness="1dp" />
</relativelayout>
</linearlayout>

这样你就可以使用圆形图片了,我们接下来看波纹的绘制

whewview

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.lgl.whew;
import java.util.arraylist;
import java.util.list;
import android.content.context;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.util.attributeset;
import android.view.view;
/**
* 模仿咻一咻
*
* @author lgl
*
*/
public class whewview extends view {
private paint paint;
private int maxwidth = 255;
// 是否运行
private boolean isstarting = false;
private list<string> alphalist = new arraylist<string>();
private list<string> startwidthlist = new arraylist<string>();
public whewview(context context, attributeset attrs, int defstyleattr) {
super(context, attrs, defstyleattr);
// todo auto-generated constructor stub
init();
}
public whewview(context context, attributeset attrs) {
super(context, attrs);
// todo auto-generated constructor stub
init();
}
public whewview(context context) {
super(context);
// todo auto-generated constructor stub
init();
}
private void init() {
paint = new paint();
// 设置博文的颜色
paint.setcolor(0x0059ccf5);
alphalist.add("255");// 圆心的不透明度
startwidthlist.add("0");
}
@override
public void ondraw(canvas canvas) {
super.ondraw(canvas);
setbackgroundcolor(color.transparent);// 颜色:完全透明
// 依次绘制 同心圆
for (int i = 0; i < alphalist.size(); i++) {
int alpha = integer.parseint(alphalist.get(i));
// 圆半径
int startwidth = integer.parseint(startwidthlist.get(i));
paint.setalpha(alpha);
// 这个半径决定你想要多大的扩散面积
canvas.drawcircle(getwidth() / 2, getheight() / 2, startwidth + 50,
paint);
// 同心圆扩散
if (isstarting && alpha > 0 && startwidth < maxwidth) {
alphalist.set(i, (alpha - 1) + "");
startwidthlist.set(i, (startwidth + 1) + "");
}
}
if (isstarting
&& integer
.parseint(startwidthlist.get(startwidthlist.size() - 1)) == maxwidth / 5) {
alphalist.add("255");
startwidthlist.add("0");
}
// 同心圆数量达到10个,删除最外层圆
if (isstarting && startwidthlist.size() == 10) {
startwidthlist.remove(0);
alphalist.remove(0);
}
// 刷新界面
invalidate();
}
// 执行动画
public void start() {
isstarting = true;
}
// 停止动画
public void stop() {
isstarting = false;
}
// 判断是都在不在执行
public boolean isstarting() {
return isstarting;
}
}

这里我们看到,对外有几个方法,一个开始动画,一个停止动画,一个检测是否正在运行

mainactivity

这里就是我们的需求了,我反编译了一下支付宝的apk,并没有找到他的咻一咻的音效,就在他的raw目录下随便找了一个,我们现在是需要这样一个需求
点击图片执行动画,并且每隔五分钟响一次
再次点击图片,停止动画,停止音效
我们先新建一个raw文件夹把音效拷贝进去吧

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.lgl.whew;
import android.app.activity;
import android.media.audiomanager;
import android.media.soundpool;
import android.os.bundle;
import android.os.handler;
import android.view.view;
import android.view.view.onclicklistener;
public class mainactivity extends activity {
private whewview wv;
private roundimageview my_photo;
private static final int nou = 1;
// 声明一个soundpool
private soundpool sp;
// 定义一个整型用load();来设置suondidf
private int music;
private handler handler = new handler() {
public void handlemessage(android.os.message msg) {
if (msg.what == nou) {
// 每隔10s响一次
handler.sendemptymessagedelayed(nou, 5000);
sp.play(music, 1, 1, 0, 0, 1);
}
}
};
@override
protected void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.activity_main);
initview();
}
private void initview() {
// 第一个参数为同时播放数据流的最大个数,第二数据流类型,第三为声音质量
sp = new soundpool(10, audiomanager.stream_system, 5);
// 把你的声音素材放到res/raw里,第2个参数即为资源文件,第3个为音乐的优先级
music = sp.load(this, r.raw.hongbao_gq, 1);
wv = (whewview) findviewbyid(r.id.wv);
my_photo = (roundimageview) findviewbyid(r.id.my_photo);
my_photo.setonclicklistener(new onclicklistener() {
@override
public void onclick(view v) {
if(wv.isstarting()){
//如果动画正在运行就停止,否则就继续执行
wv.stop();
//结束进程
handler.removemessages(nou);
}else{
// 执行动画
wv.start();
handler.sendemptymessage(nou);
}
}
});
}
}

相信这里的逻辑不是很难吧,对了,我们在结束activity的时候也是要销毁这个进程的,不然…你懂的

?
1
2
3
4
5
6
@override
protected void ondestroy() {
// todo auto-generated method stub
super.ondestroy();
handler.removemessages(nou);
}

我们运行一下,想听效果的可以下载demo运行一下,我们这里做一个简单的演示

Android波纹扩散效果之仿支付宝咻一咻功能实现波纹扩散特效