Last active
July 4, 2017 12:07
-
-
Save s1ntoneli/a06560266c09e00f3a0472d129ec1d96 to your computer and use it in GitHub Desktop.
粒子动画。从分散到集中做动画,铺开成最终图形。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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