当前位置: 移动技术网 > 移动技术>移动开发>Android > Android波纹扩散效果之仿支付宝咻一咻功能实现波纹扩散特效

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

2019年07月24日  | 移动技术网移动技术  | 我要评论

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

先来看看这个效果

这里写图片描述

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

我么新建一个工程——whew

roundimageview

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

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

<?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文件中引入命名空间

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

我们直接看layout_mian.xml吧

layout_mian.xml

就一些布局咯

<?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

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文件夹把音效拷贝进去吧

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的时候也是要销毁这个进程的,不然…你懂的

@override
protected void ondestroy() {
// todo auto-generated method stub
super.ondestroy();
handler.removemessages(nou);
}

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

这里写图片描述

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网