android实现支付宝咻一咻的几种思路方法
支付宝咻一咻在过年的时候很火热。那么咻一咻具体有哪些实现方式呢?下面我们将一一介绍这几种思路的实现过程。
1.自定义view实现咻一咻
那么这种实现方法需要掌握canvas以及paint几乎所有的方法。其对程序员的专业知识要求极高。
用该种方式实现的优点有:
㈠这种是最复杂的实现方法,但其兼容性最高,其支持android的所有设备。
㈡其对内存要求不大,几乎不占用任何内存。
下面我们来看看是怎样实现其效果的:
public class xiuyixiuview extends view { /*** * 中心图片画笔 */ private paint paint; /*** * 水波圆圈画笔 */ private paint circlepaint; /*** * 用bitmap创建画布 */ private bitmap bitmap; /*** * 中心图片 */ private bitmap imagebit; /*** * 画布 */ private canvas canvas; /*** * 屏幕的宽 */ private int screenwidth; /*** * 屏幕的高 */ private int screenheight; /*** * 图片右上角坐标 */ private point pointlefttop; /*** * 图片右下角坐标 */ private point pointrightbottom; /*** * 记录圆圈 */ private list<lyjcircle> lyjcirclelist; /*** * 标记是否按下按钮,并且源泉是否扩散消失 */ private boolean isspread=false; /*** * 默认没有按动时候的圆圈 */ private lyjcircle defaultcircle; public xiuyixiuview(context context, attributeset attrs) { super(context, attrs); this.lyjcirclelist=new arraylist<>(); screenwidth=lyjutils.getscreenwidth((activity) context); screenheight=lyjutils.getscreenheight((activity) context); bitmap = bitmap.createbitmap(screenwidth, screenheight, bitmap.config.argb_8888); // 设置位图的宽高 canvas = new canvas(); canvas.setbitmap(bitmap); paint=new paint(paint.dither_flag); paint.setantialias(true); circlepaint=new paint(paint.dither_flag); circlepaint.setantialias(true); imagebit= bitmapfactory.decoderesource(getresources(), r.drawable.bwa_homepage_yuyin); pointlefttop=new point((screenwidth/2)-(imagebit.getwidth()/2),(screenheight/2)-(imagebit.getheight()/2)); pointrightbottom=new point(pointlefttop.x+imagebit.getwidth(),pointlefttop.y+imagebit.getheight()); canvas.drawbitmap(imagebit,pointlefttop.x,pointlefttop.y,paint); //取图片上的颜色 palette.generateasync(imagebit, new palette.paletteasynclistener() { @override public void ongenerated(palette palette) { palette.swatch swatch1 = palette.getvibrantswatch(); //充满活力的色板 circlepaint.setcolor(swatch1.getrgb()); circlepaint.setstyle(paint.style.stroke); circlepaint.setstrokewidth(10); circlepaint.setalpha(100); paint.setshadowlayer(15, 0, 0, swatch1.getrgb());//设置阴影效果 int[] mcolors = new int[] {//渲染颜色 color.transparent,swatch1.getrgb() }; //范围,这里可以微调,实现你想要的渐变 float[] mpositions = new float[] { 0f, 0.1f }; shader shader=new radialgradient(screenwidth / 2,screenheight / 2,imagebit.getwidth() / 2 + 10,mcolors, mpositions, shader.tilemode.mirror); circlepaint.setshader(shader); defaultcircle=new lyjcircle(screenwidth / 2, screenheight / 2, imagebit.getwidth() / 2 + 10); clearscreenanddrawlist(); message message = handler.obtainmessage(1); handler.sendmessagedelayed(message, 1000); //发送message } }); } @override public boolean ontouchevent(motionevent event) { switch (event.getaction()){ case motionevent.action_down: break; case motionevent.action_move: break; case motionevent.action_up: isspread=true;//是否按下图片 lyjcirclelist.add(new lyjcircle(screenwidth / 2, screenheight / 2, imagebit.getwidth() / 2 + 10)); clearscreenanddrawlist(); invalidate(); break; default: break; } return true; } private handler handler = new handler(){ public void handlemessage(message msg){ switch (msg.what) { case 1: //定时更新界面 clearscreenanddrawlist(); invalidate(); message message = handler.obtainmessage(1); handler.sendmessagedelayed(message, 200); } super.handlemessage(msg); } }; /** * 清掉屏幕上所有的圆圈,然后画出集合里面的圆圈 */ private void clearscreenanddrawlist() { canvas.drawcolor(color.transparent, porterduff.mode.clear); //判断是否按下图片,并且外圈执行完成没有。 if(!isspread){ circlepaint.setmaskfilter(null); canvas.drawcircle(defaultcircle.getroundx(), defaultcircle.getroundy(),defaultcircle.getradiuloop(), circlepaint);// 画线 }else{ for (lyjcircle lyjcircle : lyjcirclelist) { if(lyjcircle.getspreadradiu()==0){ }else if(lyjcircle.getspreadradiu()>(lyjcircle.getradiu()+99)){ //如果圆圈扩散半径大于图片半径+99,那么设置边缘模糊,也就是淡出的效果 circlepaint.setmaskfilter(new blurmaskfilter(5, blurmaskfilter.blur.outer)); canvas.drawcircle(lyjcircle.getroundx(), lyjcircle.getroundy(),lyjcircle.getspreadradiu(), circlepaint);// 画线 }else{ //不是则按正常的环形渲染来 circlepaint.setmaskfilter(null); canvas.drawcircle(lyjcircle.getroundx(), lyjcircle.getroundy(),lyjcircle.getspreadradiu(), circlepaint);// 画线 } } } canvas.drawbitmap(imagebit,pointlefttop.x,pointlefttop.y,paint); //释放小时了的圆圈 for(int i=0;i<lyjcirclelist.size();i++){ if(lyjcirclelist.get(i).getspreadradiu()==0){ lyjcirclelist.remove(i); } } //如果没有点击图片发射出去的圆圈,那么就恢复默认缩放。 if(lyjcirclelist.size()<=0){ isspread=false; } } @override protected void ondraw(canvas canvas) { canvas.drawbitmap(bitmap, 0, 0, null); } }
圆类:
package com.example.liyuanjing.model; /** * created by liyuanjing on 2016/2/3. */ public class lyjcircle { private int roundx;//圆中心点x坐标 private int roundy;//圆中心点y坐标 private int radiu;//圆半径 private int currentradiu;//当前radiu private int lastradiu;//历史radiu private int spreadradiu;//加速半径 private int[] speed=new int[]{6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6};//半径扩大速度。这里为匀速 private int speedlast=0;//记录历史值 public lyjcircle(int roundx,int roundy,int radiu){ this.roundx=roundx; this.roundy=roundy; this.radiu=radiu; this.spreadradiu=radiu; this.currentradiu=this.radiu; this.lastradiu=this.currentradiu; } //获取半径 public int getradiu() { return radiu; } public void setradiu(int radiu) { this.radiu = radiu; } //获取加速半径 public int getspreadradiu(){ if(speedlast>=speed.length){ return 0; } spreadradiu+=speed[speedlast]; ++speedlast; return spreadradiu; } //获取循环缩放半径 public int getradiuloop() { if(currentradiu==lastradiu){ ++currentradiu; }else if(currentradiu>lastradiu){ if(currentradiu>(radiu+20)){ currentradiu=19+radiu; lastradiu=20+radiu; }else{ lastradiu=currentradiu; currentradiu+=5; } }else{ if(currentradiu<(radiu+9)){ currentradiu=10+radiu; lastradiu=9+radiu; }else{ lastradiu=currentradiu; currentradiu-=5; } } return currentradiu; } public int getroundx() { return roundx; } public int getroundy() { return roundy; } }
看看其效果图:
你可以修改如下两个地方,会产生视觉上真真的波纹效果:
①支付宝的背景图片是淡红色,衬托了红色的波纹。当然了你也可以将画布设置为透明淡红色。
②其为填充圆圈渲染,不是我的边框渲染效果,你可以将circlepaint.setstyle(paint.style.stroke);换成paint.style.fill.然后,微调shader的mpositions实现环形填充渐变。你也许会觉得,你看支付宝咻一咻圆圈弹开的时候内圈有波纹也像外弹开,其实那就是环形渐变,当你圆圈变大后,其渐变的范围也就变大了,自然你看到有颜色周围扩散的迹象。
2.属性动画实现咻一咻
其要掌握的只是基本只需要属性动画,在加一点线程方面有关的知识而已。
下面我们看看其实现步骤:
㈠自定义view实现一个圆即可,代码如下:
public class lyjcircleview extends view { private bitmap bitmap; private paint paint; private canvas canvas; private int screenwidth; private int screenheight; private boolean isspreadflag=false;//标记是否发射完成 public boolean isspreadflag() { return isspreadflag; } public void setisspreadflag(boolean isspreadflag) { this.isspreadflag = isspreadflag; } public lyjcircleview(context context,int width,int height,int statusheight) { super(context); screenwidth= lyjutils.getscreenwidth((activity) context); screenheight=lyjutils.getscreenheight((activity) context); bitmap = bitmap.createbitmap(screenwidth, screenheight, bitmap.config.argb_8888); // 设置位图的宽高 canvas = new canvas(); canvas.setbitmap(bitmap); paint=new paint(paint.dither_flag); paint.setantialias(true); paint.setcolor(color.red); paint.setstyle(paint.style.stroke); paint.setstrokewidth(5); paint.setalpha(100); paint.setshadowlayer(10, 0, 0, color.red); int[] mcolors = new int[] { color.transparent,color.red }; float[] mpositions = new float[] { 0f, 0.1f }; shader shader=new radialgradient(screenwidth / 2,screenheight / 2,width / 2 + 10,mcolors, mpositions, shader.tilemode.mirror); paint.setshader(shader); canvas.drawcircle(screenwidth / 2, (screenheight - statusheight) / 2, width / 2 + 10, paint); invalidate(); } @override protected void ondraw(canvas canvas) { canvas.drawbitmap(bitmap,0,0,null); } }
代码与上面差不多,就不注释了。
㈡实现activity即可
public class xiuyixiuactivity extends appcompatactivity { private imagebutton mimagebutton; private lyjcircleview lyjcircleview; private relativelayout relativelayout; private list<lyjcircleview> lyjcircleviewlist; private int statusbarheight; private animator anim; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.xiuyixiu_activity_main); this.mimagebutton=(imagebutton)findviewbyid(r.id.xiuyixiu_imagebutton); this.relativelayout=(relativelayout)findviewbyid(r.id.xiuyixiu_relativelayout); this.lyjcircleviewlist=new arraylist<>(); this.mimagebutton.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { lyjcircleview.setvisibility(view.gone);//发射圆圈,即将循环动画view隐藏 final lyjcircleview item=new lyjcircleview(xiuyixiuactivity.this, mimagebutton.getwidth(), mimagebutton.getheight(), statusbarheight); animator spreadanim = animatorinflater.loadanimator(xiuyixiuactivity.this, r.animator.circle_spread_animator); spreadanim.addlistener(new animator.animatorlistener() { @override public void onanimationstart(animator animation) { } @override public void onanimationend(animator animation) { item.setisspreadflag(true);//动画执行完成,标记一下 } @override public void onanimationcancel(animator animation) { } @override public void onanimationrepeat(animator animation) { } }); spreadanim.settarget(item); spreadanim.start(); lyjcircleviewlist.add(item); relativelayout.addview(item); relativelayout.invalidate(); message message = handler.obtainmessage(1); handler.sendmessagedelayed(message, 10); //发送message,定时释放lyjcircleview } }); } private handler handler = new handler(){ public void handlemessage(message msg){ switch (msg.what) { case 1: for(int i=0;i<lyjcircleviewlist.size();i++){ if(lyjcircleviewlist.get(i).isspreadflag()){ relativelayout.removeview(lyjcircleviewlist.get(i)); lyjcircleviewlist.remove(i); relativelayout.invalidate(); } } if(lyjcircleviewlist.size()<=0){ lyjcircleview.setvisibility(view.visible); } message message = handler.obtainmessage(1); handler.sendmessagedelayed(message, 10); } super.handlemessage(msg); } }; @override public void onwindowfocuschanged(boolean hasfocus) { super.onwindowfocuschanged(hasfocus); //获取状态栏高度 rect frame = new rect(); getwindow().getdecorview().getwindowvisibledisplayframe(frame); statusbarheight = frame.top; this.mimagebutton.post(new runnable() { @override public void run() { lyjcircleview = new lyjcircleview(xiuyixiuactivity.this, mimagebutton.getwidth(), mimagebutton.getheight(), statusbarheight); relativelayout.addview(lyjcircleview); relativelayout.postinvalidate(); // 加载动画 anim = animatorinflater.loadanimator(xiuyixiuactivity.this, r.animator.circle_scale_animator); anim.addlistener(new animator.animatorlistener() { @override public void onanimationstart(animator animation) { } @override public void onanimationend(animator animation) { anim.start();//循环执行动画 } @override public void onanimationcancel(animator animation) { } @override public void onanimationrepeat(animator animation) { } }); anim.settarget(lyjcircleview); anim.start(); } }); } }
㈢布局文件代码如下:
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/xiuyixiu_relativelayout" android:layout_width="match_parent" android:layout_height="match_parent"> <imagebutton android:id="@+id/xiuyixiu_imagebutton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerinparent="true" android:background="@drawable/bwa_homepage_yuyin"/> </relativelayout>
当然上面两个实现方法,我都只设置圆边框,没有填充,你可以设置为填充后,在微调渐变值。
其属性动画文件circle_scale_animator.xml:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together"> <objectanimator android:duration="1000" android:propertyname="scalex" android:valuefrom="1.0" android:valueto="1.2" android:valuetype="floattype"> </objectanimator> <objectanimator android:duration="1000" android:propertyname="scaley" android:valuefrom="1.0" android:valueto="1.2" android:valuetype="floattype"> </objectanimator> <objectanimator android:startoffset="1000" android:duration="1000" android:propertyname="scalex" android:valuefrom="1.2" android:valueto="1.0" android:valuetype="floattype"> </objectanimator> <objectanimator android:startoffset="1000" android:duration="1000" android:propertyname="scaley" android:valuefrom="1.2" android:valueto="1.0" android:valuetype="floattype"> </objectanimator> </set>
另一个circle_spread_animator.xml为:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectanimator android:duration="1000" android:propertyname="scaley" android:valuefrom="1.0" android:valueto="2.0" android:valuetype="floattype"> </objectanimator> <objectanimator android:duration="1000" android:propertyname="scalex" android:valuefrom="1.0" android:valueto="2.0" android:valuetype="floattype"> </objectanimator> </set>
其效果图如下:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 浅谈Java设计模式之开放封闭原则
下一篇: Java并发编程示例(三):线程中断