Let's see the effect chart first.
To achieve this effect, you need to know the Bezier curve, what is the Bezier curve? Let's start with a question mark here.
It's written directly below.
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 " >
//strewing area
<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= "beginning to sprinkle flowers"/>
</RelativeLayout>
2.Fllower
Reference class
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= "+ Valu
E + "]"; }
}
3.FllowerAnimation
Animation class
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; /** * Flowers used in the knowledge Points: 1, Android Property Animation 2, path path to draw 3, Bezier curve/public class Flloweranimation extends View implements Animatorupdat
Elistener {/** * Animation changed property value * * Private float phase1 = 0f;
private float phase2 = 0f;
private float phase3 = 0f;
/** * Small Ball set * * Private list<fllower> fllowers1 = new arraylist<fllower> (); Private List<fllower> fllowers2 = new arraylist<fllower> ();
Private list<fllower> Fllowers3 = new arraylist<fllower> ();
/** * The time of animation play * * private int times = 4000;
/** * Animation interval * * Private int delay = 400;
Int[] ylocations = {-100,-50,-25, 0};
/** * Resource ID *//private int resid = R.drawable.fllower_love;
Public Flloweranimation {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);
/** * Width/private int width = 0;
/** * Height/private int height = 0;
/** * Curve Height number segmentation/private int quadcount = 10;
/** * Curvature * * private float intensity = 0.2f;
/** * The number of the first batch * * Private int fllowercount = 4; /** * Create flower/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); }/** * Draw curve * @param path * @param points/private void Drawfllowerpath (PaTh path, list<cpoint> points) {if (Points.size () > 1) {for (int j = 0; J < Points.size (); j + +) {Cpoin
T 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); /** * Curve swing amplitude/private int range = (int) typedvalue. Applydimension (Typedvalue.
Complex_unit_dip, Getresources (), Getdisplaymetrics ()); /** * Draw Path * * @param point * @return/private list<cpoint> Builderpath (CPoint point) {list<cpoint> P
oints = 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% 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;
/** * Brush/private Paint mpaint;
/** * The coordinate position of the measuring path * * Private pathmeasure pathmeasure = null;
@Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
Drawfllower (canvas, fllowers1);
Drawfllower (canvas, fllowers2);
Drawfllower (canvas, FLLOWERS3); /** * Height upward offset, move the start point out of the top of the screen * * private float dy = typedvalue.applydimension (typedvalue.complex_unit_dip, 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], 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); /** * With the location of the new ball * * @param value * @param fllowers/private void Updatevalue (float value, list<fllower> FL
Lowers) {for (Fllower fllower:fllowers) {fllower.setvalue (value); }/** * Animation change callback/@Override public void Onanimationupdate (Valueanimator arg0) {updatevalue (), getPhase1
RS1);
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
Then we'll see if we use
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;
Sprinkle special effects private relativelayout rlt_animation_layout;
Private Flloweranimation flloweranimation;
@Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_main);
Strewing initialization 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) {//start to sprinkle flowers Flloweranima
Tion.startanimation ();
}
});
}
}
Okay, let's look at the effect now.
The source of the hit: Android imitation QQ chat mosaic special effects
OK, you should go and have a try! We can make similar snowflakes falling effect, try!