Not much, first on the effect map, feel simple, please spray lightly.
My wife exploded... Oh no, there are many particles moving after the image explosion, so each particle is an object. First, the particle is defined as a particle object. The particle is circular, first is the color of the particle, then is the center coordinate and radius of the particle, which has been able to determine a particle. Then the particle needs to be accelerated and accelerated after the explosion. Speed, top code
public class Ball { public int color; //Pixel Pixel Color Value public float x; //Particle center coordinate x public float y; //Particle center coordinate y public float r; //Particle radius public float vX;//Horizontal velocity of particle motion public float vY;//Vertical velocity of particle motion public float aX;//Horizontal acceleration of particle motion public float aY;//Vertical acceleration of particle motion }
Then we start to implement the idea. First, we define SplitView to inherit from View, initialize a brush in the constructor, initially draw a BitMap to explode, and then sample the BitMap. We define the radius of the particle as 15px, that is, every 2*15 pixels, sample a color value, and then the whole particle's face. The color is sampled according to the color value. The center coordinate of the particle is the coordinate of the sampling point. Then the initial horizontal and vertical velocities of the particle are randomly generated by random numbers from - 20 to 20. We simulate the real explosion. The horizontal acceleration is set to 0, and the vertical acceleration is set to 6. Of course, you can also give it to the real explosion. Larger or smaller, define a list of Ball s to hold the initial state of the balls, and code it.
private void init() { mPaint = new Paint(); balls = new ArrayList<>(); mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.girl); int width = mBitmap.getWidth(); int height = mBitmap.getHeight(); Random random = new Random(); for (int i = 0; i < width; i += 2 * r) { for (int j = 0; j < height; j += 2 * r) { Ball ball = new Ball(); ball.color = mBitmap.getPixel(i, j); ball.x = i; ball.y = j; ball.r = r; ball.vX = random.nextInt(39) + random.nextFloat() - 20.0f;//(-20 , 20) ball.vY = random.nextInt(39) + random.nextFloat() - 20.0f;//(-20 , 20) ball.aX = 0; ball.aY = 6f; balls.add(ball); } } }
Now that all the particles have been initialized, a switch Boolean value isSplit is defined to determine whether the explosion started. Then we start drawing bitmap before the explosion started. If the explosion started, we draw the particle set instead of drawing bitmap.
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (!isSplit) { canvas.drawBitmap(mBitmap, 0, 0, mPaint); } else { for (Ball ball : balls) { mPaint.setColor(ball.color); canvas.drawCircle(ball.x, ball.y, ball.r, mPaint); } } }
Well, now that everything is ready, there's still one trigger missing. That's when the explosion happens and how the coordinates of the particles change after the explosion. For simplicity, start exploding after clicking on view.
@Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { updateBall(); } return super.onTouchEvent(event); }
The trigger condition is also there. Do you think that if you click on the screen now, he will move? No, you haven't defined how to move. So if you click on the screen now, the ball will not be used. Next, let's see how to update the coordinates. First, we need to change the marker isSplit to true. Then, we need to create a new attribute animation to let the attribute animation play circularly. We change the abscissa and ordinate of each particle in a circular way, then call invalidate method, invalidate method calls ondraw method of view, the particle is redrawn, so the particle moves.
private void updateBall() { isSplit = true; ValueAnimator animator = ValueAnimator.ofFloat(0, 1); animator.setDuration(30); animator.setRepeatCount(-1); animator.setInterpolator(new LinearInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { for (Ball ball : balls) { ball.x += ball.vX; ball.y += ball.vY; ball.vX += ball.aX; ball.vY += ball.aY; Log.d(TAG, "onAnimationUpdate: "); } invalidate(); } }); animator.start(); }
Complete SplitView code:
public class SplitView extends View { private static final String TAG = "SplitView"; private Paint mPaint; private float r = 15f;//Radius of particles after explosion private boolean isSplit = false;//Does it start to explode? List<Ball> balls; private Bitmap mBitmap; public SplitView(Context context) { this(context, null); } public SplitView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public SplitView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaint = new Paint(); balls = new ArrayList<>(); mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.girl); int width = mBitmap.getWidth(); int height = mBitmap.getHeight(); Random random = new Random(); for (int i = 0; i < width; i += 2 * r) { for (int j = 0; j < height; j += 2 * r) { Ball ball = new Ball(); ball.color = mBitmap.getPixel(i, j); ball.x = i; ball.y = j; ball.r = r; ball.vX = random.nextInt(39) + random.nextFloat() - 20.0f;//(-20 , 20) ball.vY = random.nextInt(39) + random.nextFloat() - 20.0f;//(-20 , 20) ball.aX = 0; ball.aY = 6f; balls.add(ball); } } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (!isSplit) { canvas.drawBitmap(mBitmap, 0, 0, mPaint); } else { for (Ball ball : balls) { mPaint.setColor(ball.color); canvas.drawCircle(ball.x, ball.y, ball.r, mPaint); } } } private void updateBall() { isSplit = true; ValueAnimator animator = ValueAnimator.ofFloat(0, 1); animator.setDuration(30); animator.setRepeatCount(-1); animator.setInterpolator(new LinearInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { for (Ball ball : balls) { ball.x += ball.vX; ball.y += ball.vY; ball.vX += ball.aX; ball.vY += ball.aY; Log.d(TAG, "onAnimationUpdate: "); } invalidate(); } }); animator.start(); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { updateBall(); } return super.onTouchEvent(event); } }
Attached Demo: https://github.com/987570437/PaintDemo