Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
This article also participated in the “Digitalstar Project” to win a creative gift package and creative incentive money.
There are a lot of vertical water ripple progress bars on the Internet, but few horizontal ones. There are still some troubles in changing the vertical water ripple to horizontal ones. Now it is released after completion, hoping that fewer people will lie in pits.
Thought analysis
The overall effect can be divided into three parts: draw the rounded background and rounded rectangle, draw the first and second water waves, and change the effect according to custom progress.
Function implementation
1. Draw a rounded background and rounded rectangle border
Rounded rectangle border:
private RectF rectBorder;
if (rectBorder == null) {
rectBorder = new RectF(0.5 f * dp1, 0.5 f * dp1, waveActualSizeWidth - 0.5 f * dp1, waveActualSizeHeight - 0.5 f * dp1);
}
canvas.drawRoundRect(rectBorder, dp27, dp27, borderPaint);
Copy the code
We create a new canvas and fill it with a rounded rectangle background and the first and second water waves:
// The cache is used to create a new bitmap based on the parameters
if (circleBitmap == null) {
circleBitmap = Bitmap.createBitmap(waveActualSizeWidth, waveActualSizeHeight, Bitmap.Config.ARGB_8888);
}
// Create a canvas based on the bitmap
if (bitmapCanvas == null) {
bitmapCanvas = new Canvas(circleBitmap);
}
// Rounded rectangle background, in order to allow waves to fill the full circle background
if (rectBg == null) {
rectBg = new RectF(0.0, waveActualSizeWidth, waveActualSizeHeight);
}
bitmapCanvas.drawRoundRect(rectBg, dp27, dp27, backgroundPaint);
// Crop the image
canvas.drawBitmap(circleBitmap, 0.0.null);
Copy the code
2. Realize double water wave through Bezier curve
1) Realize the first water wave
/** * draw wavy lines */
private Path canvasWavePath(a) {
Clear the route first
wavePath.reset();
// the starting point moves to (0,0) p0-p1 height as the progress changes
wavePath.moveTo((currentPercent) * waveActualSizeWidth, -moveDistance);
// The maximum number of waves can be drawn
I < getWidth(); I +=waveLength is not perfect
// Draw p0-p1 draw a wavy line. There is a segment that is outside the View, to the right of the View margin, so it is * 2
for (int i = 0; i < waveNumber * 2; i++) {
wavePath.rQuadTo(waveHeight, waveLength / 2.0, waveLength);
wavePath.rQuadTo(-waveHeight, waveLength / 2.0, waveLength);
}
// connect p1-p2
wavePath.lineTo(0, waveActualSizeHeight);
// Connect p2-P0
wavePath.lineTo(0.0);
// Close and fill
wavePath.close();
return wavePath;
}
Copy the code
MoveDistance is the vertical movement distance of water wave. WaveLength refers to the length of water waves, one upper arc plus one lower arc. The path starts at (0,0), which can be dynamically changed according to progress, and then draws a loop with a length of several waves, then connects to the height of the view, and finally reaches (0,0), forming a closed area, thus achieving a filled water wave effect.
2) Draw the second wave, which is similar to the first wave except that the starting point is changed:
/** * draw the second wave */
private Path canvasSecondPath(a) {
secondWavePath.reset();
// The initial point moves down
secondWavePath.moveTo((currentPercent) * waveActualSizeWidth, waveActualSizeHeight + moveDistance);
for (int i = 0; i < waveNumber * 2; i++) {
secondWavePath.rQuadTo(waveHeight, -waveLength / 2.0, -waveLength);
secondWavePath.rQuadTo(-waveHeight, -waveLength / 2.0, -waveLength);
}
secondWavePath.lineTo(0.0);
secondWavePath.lineTo(0, waveActualSizeHeight);
secondWavePath.close();
return secondWavePath;
}
Copy the code
3. Set the animation to make progress and ripples change
/** * Set the progress **@paramCurrentProgress progress *@paramDuration Time required to reach the progress */
public void setProgress(int currentProgress, long duration, AnimatorListenerAdapter listenerAdapter) {
float percent = currentProgress * 1f / maxProgress;
this.currentProgress = currentProgress;
// Change from 0
currentPercent = 0;
moveDistance = 0;
mProgressAnimator = ValueAnimator.ofFloat(0, percent);
// Set the animation time
mProgressAnimator.setDuration(duration);
// Let the animation play at a uniform speed to avoid the phenomenon of waves moving and stopping
mProgressAnimator.setInterpolator(new LinearInterpolator());
mProgressAnimator.addUpdateListener(listener);
mProgressAnimator.addListener(listenerAdapter);
mProgressAnimator.start();
/ / wavy lines
startWaveAnimal();
}
/** * wave animation */
private void startWaveAnimal(a) {
// Animate instantiate
if (waveProgressAnimator == null) {
waveProgressAnimator = new WaveProgressAnimal();
// Set the animation time
waveProgressAnimator.setDuration(2000);
// Set the loop to play
waveProgressAnimator.setRepeatCount(Animation.INFINITE);
// Let the animation play at a uniform speed to avoid the phenomenon of waves moving and stopping
waveProgressAnimator.setInterpolator(new LinearInterpolator());
// Animation is enabled for the current view
this.startAnimation(waveProgressAnimator); }}Copy the code
The wave animation is achieved by changing the value of moveDistance to change the ordinate, and the progress is mainly achieved by changing the currentPercent to change the abscissa of the wave.
conclusion
Through this project, we can mainly learn Bezier curves, and also match different animations to deal with various interactive effects of products. The corresponding files: HorizontalWaveProgressView. Java