Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw round rect stroke animation

Currently diving into Canvas and drawing custom views. I just created a round rect with border with this code (my onDraw method):

paint.color = Color.RED
paint.style = Paint.Style.FILL
val cornerRadius = 150f
val strokeWidth = 12f
val rect = RectF(
   rootView.left.toFloat() + strokeWidth,
   rootView.top.toFloat() + strokeWidth,
   rootView.right.toFloat() - strokeWidth,
   rootView.bottom.toFloat() - strokeWidth
)
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint)
paint.style = Paint.Style.STROKE
paint.color = Color.GREEN
paint.strokeWidth = strokeWidth
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint)

What I want to achieve is animation (snake-like progress) for this border. Last time I did something similar was circle border animation where drawArc with the dynamically changed angle in the Animation object did the perfect job. However, this time I cannot use drawArc because the different shape is required. I attach an image where I pointed out where I want the animation to start. I was thinking about creating Path object but I have no idea how to start drawing from the right bottom corner (just after the rounded part). Did anyone work with something similar already?

Last time (for the circle, as mentioned before) I did something like this:

canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint)

and the Animation class:

    private inner class CountdownAnimation(private val roundCountdownView: RoundCountdownView): Animation() {

        override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
            roundCountdownView.angle = 360f * interpolatedTime
            roundCountdownView.requestLayout()
        }
    }

I would like to achieve something similar but cannot find anything useful on the Internet. Found already this SO question but I think that doing it via bitmaps is overkill for this specific problem. I will appreciate any suggestions. Thanks in advance! :)

like image 673
shurrok Avatar asked Oct 25 '25 05:10

shurrok


1 Answers

Finally found a super clean way after searching different similar questions. First, change the drawRoundRect into a path like:

    final Path path = new Path();
    path.addRoundRect(rect, corners, Path.Direction.CW);
    // Draw 
    canvas.drawPath(path, p);

and then now you want to be able to get different progress points of the path using this:

private Path getSubPath(Path path, float start, float end) {
    Path subPath = new Path();
    PathMeasure pathMeasure = new PathMeasure(path, false);
    pathMeasure.getSegment(start * pathMeasure.getLength(), end * pathMeasure.getLength(), subPath, true);
    return subPath;
}

an example of usage to draw 75% of the path would be:

 canvas.drawPath(getSubPath(path, 0, 0.75), mLinePaint);

By now i'm sure you know where I'm going. Finally to put it together, use the ValueAnimator.ofFloat to animate 0 - 1.0f.

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
        valueAnimator.setDuration(5000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mCurrentPathProgress = (float) valueAnimator.getAnimatedValue();
                requestLayout();
            }
        });
        valueAnimator.start();

and finally in your onDraw method:

canvas.drawPath(getSubPath(path, 0, mCurrentPathProgress), mLinePaint);
like image 135
Jessicardo Avatar answered Oct 26 '25 17:10

Jessicardo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!