Android仿QQ聊天撒花特效 很真实
程序员文章站
2024-03-02 12:52:58
先看看效果图吧
实现这样的效果,你要知道贝塞尔曲线,何谓贝塞尔曲线?先在这里打个问号
下面就直接写了
1.activity_main.xml
先看看效果图吧
实现这样的效果,你要知道贝塞尔曲线,何谓贝塞尔曲线?先在这里打个问号
下面就直接写了
1.activity_main.xml
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > //撒花的区域 <relativelayout android:id="@+id/rlt_animation_layout" android:layout_width="match_parent" android:layout_height="match_parent" > </relativelayout> <button android:id="@+id/btn_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparentbottom="true" android:layout_centerhorizontal="true" android:layout_marginbottom="23dp" android:text="开始撒花" /> </relativelayout>
2.fllower
传参类
package com.lgl.test; import android.graphics.bitmap; import android.graphics.path; import java.io.serializable; public class fllower implements serializable { private static final long serialversionuid = 1l; private bitmap image; private float x; private float y; private path path; private float value; public bitmap getresid() { return image; } public void setresid(bitmap img) { this.image = img; } public float getx() { return x; } public void setx(float x) { this.x = x; } public float gety() { return y; } public void sety(float y) { this.y = y; } public path getpath() { return path; } public void setpath(path path) { this.path = path; } public float getvalue() { return value; } public void setvalue(float value) { this.value = value; } @override public string tostring() { return "fllower [ x=" + x + ", y=" + y + ", path=" + path + ", value=" + value + "]"; } }
3.flloweranimation
动画类
package com.lgl.test; import java.util.arraylist; import java.util.list; import java.util.random; import android.animation.objectanimator; import android.animation.valueanimator; import android.animation.valueanimator.animatorupdatelistener; import android.content.context; import android.graphics.bitmap; import android.graphics.bitmapfactory; import android.graphics.canvas; import android.graphics.paint; import android.graphics.path; import android.graphics.pathmeasure; import android.util.log; import android.util.typedvalue; import android.view.view; import android.view.windowmanager; import android.view.animation.accelerateinterpolator; /** * 撒花 用到的知识点: 1、android属性动画 2、path路径绘制 3、贝塞尔曲线 */ public class flloweranimation extends view implements animatorupdatelistener { /** * 动画改变的属性值 */ private float phase1 = 0f; private float phase2 = 0f; private float phase3 = 0f; /** * 小球集合 */ private list<fllower> fllowers1 = new arraylist<fllower>(); private list<fllower> fllowers2 = new arraylist<fllower>(); private list<fllower> fllowers3 = new arraylist<fllower>(); /** * 动画播放的时间 */ private int time = 4000; /** * 动画间隔 */ private int delay = 400; int[] ylocations = { -100, -50, -25, 0 }; /** * 资源id */ // private int resid = r.drawable.fllower_love; public flloweranimation(context context) { super(context); init(context); // this.resid = resid; } @suppresswarnings("deprecation") private void init(context context) { windowmanager wm = (windowmanager) context .getsystemservice(context.window_service); width = wm.getdefaultdisplay().getwidth(); height = (int) (wm.getdefaultdisplay().getheight() * 3 / 2f); mpaint = new paint(); mpaint.setantialias(true); // mpaint.setstrokewidth(2); // mpaint.setcolor(color.blue); // mpaint.setstyle(style.stroke); pathmeasure = new pathmeasure(); builderfollower(fllowercount, fllowers1); builderfollower(fllowercount, fllowers2); builderfollower(fllowercount, fllowers3); } /** * 宽度 */ private int width = 0; /** * 高度 */ private int height = 0; /** * 曲线高度个数分割 */ private int quadcount = 10; /** * 曲度 */ private float intensity = 0.2f; /** * 第一批个数 */ private int fllowercount = 4; /** * 创建花 */ private void builderfollower(int count, list<fllower> fllowers) { int max = (int) (width * 3 / 4f); int min = (int) (width / 4f); random random = new random(); for (int i = 0; i < count; i++) { int s = random.nextint(max) % (max - min + 1) + min; path path = new path(); cpoint cpoint = new cpoint(s, ylocations[random.nextint(3)]); list<cpoint> points = builderpath(cpoint); drawfllowerpath(path, points); fllower fllower = new fllower(); fllower.setpath(path); bitmap bitmap = bitmapfactory.decoderesource(getresources(), r.drawable.lift_flower); fllower.setresid(bitmap); fllowers.add(fllower); } } /** * 画曲线 * * @param path * @param points */ private void drawfllowerpath(path path, list<cpoint> points) { if (points.size() > 1) { for (int j = 0; j < points.size(); j++) { cpoint point = points.get(j); if (j == 0) { cpoint next = points.get(j + 1); point.dx = ((next.x - point.x) * intensity); point.dy = ((next.y - point.y) * intensity); } else if (j == points.size() - 1) { cpoint prev = points.get(j - 1); point.dx = ((point.x - prev.x) * intensity); point.dy = ((point.y - prev.y) * intensity); } else { cpoint next = points.get(j + 1); cpoint prev = points.get(j - 1); point.dx = ((next.x - prev.x) * intensity); point.dy = ((next.y - prev.y) * intensity); } // create the cubic-spline path if (j == 0) { path.moveto(point.x, point.y); } else { cpoint prev = points.get(j - 1); path.cubicto(prev.x + prev.dx, (prev.y + prev.dy), point.x - point.dx, (point.y - point.dy), point.x, point.y); } } } } /** * 曲线摇摆的幅度 */ private int range = (int) typedvalue .applydimension(typedvalue.complex_unit_dip, 70, getresources() .getdisplaymetrics()); /** * 画路径 * * @param point * @return */ private list<cpoint> builderpath(cpoint point) { list<cpoint> points = new arraylist<cpoint>(); random random = new random(); for (int i = 0; i < quadcount; i++) { if (i == 0) { points.add(point); } else { cpoint tmp = new cpoint(0, 0); if (random.nextint(100) % 2 == 0) { tmp.x = point.x + random.nextint(range); } else { tmp.x = point.x - random.nextint(range); } tmp.y = (int) (height / (float) quadcount * i); points.add(tmp); } } return points; } /** * 画笔 */ private paint mpaint; /** * 测量路径的坐标位置 */ private pathmeasure pathmeasure = null; @override protected void ondraw(canvas canvas) { super.ondraw(canvas); drawfllower(canvas, fllowers1); drawfllower(canvas, fllowers2); drawfllower(canvas, fllowers3); } /** * 高度往上偏移量,把开始点移出屏幕顶部 */ private float dy = typedvalue.applydimension(typedvalue.complex_unit_dip, 40, getresources().getdisplaymetrics()); /** * @param canvas * @param fllowers */ private void drawfllower(canvas canvas, list<fllower> fllowers) { for (fllower fllower : fllowers) { float[] pos = new float[2]; // canvas.drawpath(fllower.getpath(),mpaint); pathmeasure.setpath(fllower.getpath(), false); pathmeasure.getpostan(height * fllower.getvalue(), pos, null); // canvas.drawcircle(pos[0], pos[1], 10, mpaint); canvas.drawbitmap(fllower.getresid(), pos[0], pos[1] - dy, null); } } objectanimator manimator1; objectanimator manimator2; objectanimator manimator3; public void startanimation() { if (manimator1 != null && manimator1.isrunning()) { manimator1.cancel(); } manimator1 = objectanimator.offloat(this, "phase1", 0f, 1f); manimator1.setduration(time); manimator1.addupdatelistener(this); manimator1.start(); manimator1.setinterpolator(new accelerateinterpolator(1f)); if (manimator2 != null && manimator2.isrunning()) { manimator2.cancel(); } manimator2 = objectanimator.offloat(this, "phase2", 0f, 1f); manimator2.setduration(time); manimator2.addupdatelistener(this); manimator2.start(); manimator2.setinterpolator(new accelerateinterpolator(1f)); manimator2.setstartdelay(delay); if (manimator3 != null && manimator3.isrunning()) { manimator3.cancel(); } manimator3 = objectanimator.offloat(this, "phase3", 0f, 1f); manimator3.setduration(time); manimator3.addupdatelistener(this); manimator3.start(); manimator3.setinterpolator(new accelerateinterpolator(1f)); manimator3.setstartdelay(delay * 2); } /** * 跟新小球的位置 * * @param value * @param fllowers */ private void updatevalue(float value, list<fllower> fllowers) { for (fllower fllower : fllowers) { fllower.setvalue(value); } } /** * 动画改变回调 */ @override public void onanimationupdate(valueanimator arg0) { updatevalue(getphase1(), fllowers1); updatevalue(getphase2(), fllowers2); updatevalue(getphase3(), fllowers3); log.i(tag, getphase1() + ""); invalidate(); } public float getphase1() { return phase1; } public void setphase1(float phase1) { this.phase1 = phase1; } public float getphase2() { return phase2; } public void setphase2(float phase2) { this.phase2 = phase2; } public float getphase3() { return phase3; } public void setphase3(float phase3) { this.phase3 = phase3; } private string tag = this.getclass().getsimplename(); private class cpoint { public float x = 0f; public float y = 0f; /** * x-axis distance */ public float dx = 0f; /** * y-axis distance */ public float dy = 0f; public cpoint(float x, float y) { this.x = x; this.y = y; } } }
4.mainactivity
接着就看我们使用
package com.lgl.test; import android.app.activity; import android.os.bundle; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; import android.widget.relativelayout; public class mainactivity extends activity { private button btn_start; // 撒花特效 private relativelayout rlt_animation_layout; private flloweranimation flloweranimation; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); // 撒花初始化 rlt_animation_layout = (relativelayout) findviewbyid(r.id.rlt_animation_layout); rlt_animation_layout.setvisibility(view.visible); flloweranimation = new flloweranimation(this); relativelayout.layoutparams params = new relativelayout.layoutparams( relativelayout.layoutparams.match_parent, relativelayout.layoutparams.match_parent); flloweranimation.setlayoutparams(params); rlt_animation_layout.addview(flloweranimation); btn_start = (button) findviewbyid(r.id.btn_start); btn_start.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { // 开始撒花 flloweranimation.startanimation(); } }); } }
好,我们现在来看看效果
源码下砸:android仿qq聊天撒花特效
好的,你也赶快去试一下吧!大家可以制作类似的雪花飘落效果等,try!
上一篇: 读《精通spring》第四章
下一篇: mysql的启动过程详解