Skip to content

Instantly share code, notes, and snippets.

@s1ntoneli
Last active July 4, 2017 12:07
Show Gist options
  • Select an option

  • Save s1ntoneli/a06560266c09e00f3a0472d129ec1d96 to your computer and use it in GitHub Desktop.

Select an option

Save s1ntoneli/a06560266c09e00f3a0472d129ec1d96 to your computer and use it in GitHub Desktop.
粒子动画。从分散到集中做动画,铺开成最终图形。
package com.sctdroid.app.uikit;
import android.animation.ValueAnimator;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by lixindong on 6/27/17.
*/
public class Particle extends Drawable implements Animatable, ValueAnimator.AnimatorUpdateListener {
private Bitmap mBitmap;
private ValueAnimator mAnimator;
private List<ValueAnimator> mParticleAnimators = new ArrayList<>();
private int duration = 1250;
private int drawnDuration = 500;
private int randomDuration = 500;
public Particle(@NonNull Bitmap bitmap) {
mBitmap = bitmap.copy(bitmap.getConfig(), true);
pointPaint = new Paint();
rectPaint = new Paint();
mAnimator = ValueAnimator.ofInt(0, mBitmap.getWidth());
mAnimator.setDuration(duration);
mAnimator.setInterpolator(new AccelerateInterpolator());
updateParticles();
}
private List<ParticleElement> elements = new ArrayList<>();
int len = 16;
private void updateParticles() {
elements.clear();
for (int x = 0; x < mBitmap.getWidth(); x += len) {
for (int y = 0; y < mBitmap.getHeight(); y += len) {
int color = mBitmap.getPixel(x, y);
int r = Color.red(color);
int a = Color.alpha(color);
int g = Color.green(color);
int b = Color.blue(color);
if (r >= 250 && g >= 250 && b >= 250) {
continue;
}
int fixedX = (int) (x + (Math.random() - 0.5) * 30);
int fixedY = (int) (y + (Math.random() - 0.5) * 30);
elements.add(new ParticleElement(fixedX, fixedY, color));
}
}
}
private Paint pointPaint;
private Paint rectPaint;
@Override
public void draw(@NonNull Canvas canvas) {
canvas.save();
canvas.clipRect(0, 0, clipWidth, canvas.getHeight());
canvas.drawBitmap(mBitmap, 0, 0, null);
if (isRunning()) {
LinearGradient gradient = new LinearGradient(0, 0, 100, 0, Color.TRANSPARENT, Color.parseColor("#11ffffff"), Shader.TileMode.CLAMP);
rectPaint.setShader(gradient);
rectPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));
canvas.save();
canvas.translate(clipWidth - 100, 0);
canvas.drawRect(0, 0, 100, canvas.getHeight(), rectPaint);
canvas.restore();
rectPaint.setXfermode(null);
}
canvas.restore();
for (ParticleElement element : elements) {
if (element.visible) {
pointPaint.setColor(element.color);
canvas.drawCircle(element.x, element.y, len / 4, pointPaint);
}
}
}
@Override
public int getIntrinsicWidth() {
return mBitmap.getWidth();
}
@Override
public int getIntrinsicHeight() {
return mBitmap.getHeight();
}
@Override
public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return 0;
}
Interpolator interpolator = new DecelerateInterpolator(1.3f);
@Override
public void start() {
clipWidth = 0;
for (final ParticleElement element : elements) {
final int controllerX = (int) (getIntrinsicWidth() + 300 * (Math.random() - 0.5));
final int controllerY = (int) (element.y * Math.random());
final int endX = element.x;
final int endY = element.y;
final int startX = (int) (getIntrinsicWidth() + 100 * (Math.random() - 0.5));
final int startY = 0;
ValueAnimator animator = ValueAnimator.ofInt(0, element.y);
animator.setDuration(drawnDuration);
animator.setStartDelay(duration * element.x / getIntrinsicWidth() + (long) (Math.random() * randomDuration));
animator.setInterpolator(interpolator);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if (animation.getAnimatedFraction() == 0) {
element.visible = true;
}
Point point = bazic(startX, startY, controllerX, controllerY, endX, endY, animation.getAnimatedFraction());
element.x = point.x;
element.y = point.y;
if (animation.getAnimatedFraction() == 1) {
element.visible = false;
}
invalidateSelf();
}
});
mParticleAnimators.add(animator);
animator.start();
}
mAnimator.addUpdateListener(this);
mAnimator.setStartDelay(drawnDuration);
mAnimator.start();
}
private Point bazic(int p1x, int p1y, int controllerX, int controllerY, int p2x, int p2y, float t) {
int x = (int) ((1-t)*(1-t)*p1x + 2 * t * (1-t) * controllerX + t * t * p2x);
int y = (int) ((1-t)*(1-t)*p1y + 2 * t * (1-t) * controllerY + t * t * p2y);
return new Point(x, y);
}
@Override
public void stop() {
mAnimator.removeUpdateListener(this);
mAnimator.end();
}
@Override
public boolean isRunning() {
return mAnimator.isRunning();
}
private int clipWidth = 0;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
clipWidth = (int) ((int) animation.getAnimatedValue() + 100 * animation.getAnimatedFraction());
invalidateSelf();
}
private class ParticleElement {
public int x;
public int y;
public final int color;
public boolean visible = false;
private ParticleElement(int x, int y, int color) {
this.x = x;
this.y = y;
this.color = color;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment