Search code examples
androidlineandroid-canvasandroid-jetpack-compose

Length of line is more than the canvas it is drawn in (Jetpack Compose)


I have created a progressbar with a line that grows from a certain start point to a certain end point.

The following pic shows how my progressbar looks like:

Progressbar

The problem is that the line gets drawn beyond the width of canvas used for drawing it. I have set the width of canvas only upto the smiley in the above pic, but the growing line exceeds it.

This code is used to create a LaunchedEffect used while drawing the growing line:

    val animatedProgress = remember { Animatable(0.001f) }
    val context = LocalContext.current
    LaunchedEffect(animatedProgress) {
        animatedProgress.animateTo(
            1f,
            animationSpec = repeatable(
                1,
                animation = tween(durationMillis = 3000, easing = LinearEasing)
            )
        )
    }

Code to draw static line:

  //Below canvas draws a static line for a certain length
    Canvas(modifier = Modifier.constrainAs(staticLineCanvas){
        top.linkTo(firstCircle.top)
        bottom.linkTo(firstCircle.bottom)
        start.linkTo(firstCircle.end)
    }){
        drawLine(
            cap = StrokeCap.Round,
            strokeWidth = 4.39.dp.toPx(),
            color = bright_green,
            start = Offset(0f, 0f),
            end = Offset(680f, 0f)
        )
    }

Code to draw growing line:

    //Below canvas draws the actual growing line
    Canvas(modifier = Modifier
        .padding(start = 80.dp) //Padding to draw line from the end of static line
        .constrainAs(animatedLineCanvas)
        {
            top.linkTo(secondCircle.top)
            bottom.linkTo(secondCircle.bottom)
            start.linkTo(secondCircle.end)
            end.linkTo(thirdCircle.start)
            width = Dimension.fillToConstraints
        }) {
        val startingPoint = Offset(0f, 0f)
        val endingPoint =
            Offset(adaptDimenToMultScreens(100.0f, context) * animatedProgress.value, 0f)
//adaptDimenToMultScreens() is supposed to convert value to fit the current screen size.           
        drawLine(
            cap = StrokeCap.Round,
            strokeWidth = 4.39.dp.toPx(),
            color = bright_green,
            start = startingPoint,
            end = endingPoint
        )
    }

"adaptDimenToMultScreens()" is supposed to convert value to fit the current screen size (which is probably not working).

Code for adaptDimenToMultScreens():

fun adaptDimenToMultScreens(value:Float, context: Context) : Float{
    val pixels = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        value,
        context.getResources().getDisplayMetrics()
    )

    return pixels
}

How do I make the growing line not exceed the canvas (i.e draw it only upto the smiley shown in pic above)?


Solution

  • Solved it by using 'width of canvas' times animatedProgress in ending point for animation.

    So, instead of this:

     val endingPoint = Offset(adaptDimenToMultScreens(100.0f, context) * animatedProgress.value, 0f)
    

    I did:

    val endingPoint = Offset(animCanvasWidth * animatedProgress.value, animCanvasHeight/2)
    

    Calculated 'animCanvasWidth' and 'animCanvasHeight' as:

    Canvas(modifier = Modifier
                    .constrainAs(animatedLineCanvas)
                    {
                        top.linkTo(secondCircle.top)
                        bottom.linkTo(secondCircle.bottom)
                        start.linkTo(secondCircle.end)
                        end.linkTo(thirdCircle.start)
                        width = Dimension.fillToConstraints
                    }
                    .onGloballyPositioned { coordinates ->
                        animCanvasWidth = coordinates.size.toSize().width
                        animCanvasHeight = coordinates.size.toSize().height
    
                    }
                ) {
                   .
                   .
                   .
                   }