Hey, I'm running into an issue with drawing text ...
# compose-android
b
Hey, I'm running into an issue with drawing text on a canvas. I'm drawing some chart-like graphics (rectangles, lines and text), and the size will scale with content. I am limiting the size of the canvas though to a specified max. My goal is to specify the
.size()
on the canvas and use clipping so that the drawing functions don't have to care about the size of the canvas, they just draw their full content as normal. This is working fine for shapes (rectangles, lines), but when I try to
drawText
, as soon as it gets too far outside the limits of the canvas size, it throws an
IllegalArgumentException: maxWidth must be >= than minWidth, maxHeight must be >= 0
. Im not sure why it does this, is there a workaround so that I can still avoid having a bunch of size checking logic in the drawing functions?
r
The way you'd normally do this is have the
Canvas
be just the size it needs to be on screen. The rest is handled with translation/scaling of the drawing operations
b
that's what im trying to do
r
Can you share some of your code?
b
minus the scaling (for now), the chart will be larger than the canvas size and I was going to implement touch panning
r
Can you share some of your code please and also the stack trace?
b
the code is split up and hard to share in here, the basic canvas part is just this:
Copy code
val measurer = rememberTextMeasurer()


            // need to manually calc the canvas height
            val density = LocalDensity.current
            val canvasHeight = remember(density) {
                measureHeight(
                    systems = systems,
                    measurer = measurer,
                    context = context,
                    density = density
                ).coerceAtMost(max)
            }

            Spacer(
                modifier = Modifier
                    .padding(10.dp)
                    .border(width = 1.dp, color = Color.DarkGray)
                    .height(canvasHeight)
                    .fillMaxWidth()
                    .drawWithCache {

                        onDrawBehind {
                            //... drawing functions
                        }
                    }
im just drawing a random thing outside the window to test the exception:
Copy code
drawText(
        textMeasurer = measurer,
        text = "name",
        topLeft = Offset(x = 50f, y = 540f),
        style = context.labelStyle,
        softWrap = false,
        overflow = TextOverflow.Visible
    )
the exception is:
Copy code
java.lang.IllegalArgumentException: maxWidth must be >= than minWidth,
                                                                                                    maxHeight must be >= than minHeight,
                                                                                                    minWidth and minHeight must be >= 0
                                                                                                    	at androidx.compose.ui.unit.InlineClassHelperKt.throwIllegalArgumentException(InlineClassHelper.kt:30)
                                                                                                    	at androidx.compose.ui.unit.ConstraintsKt.Constraints(Constraints.kt:638)
                                                                                                    	at androidx.compose.ui.text.TextPainterKt.textLayoutConstraints-v_w8tDc(TextPainter.kt:387)
                                                                                                    	at androidx.compose.ui.text.TextPainterKt.drawText-TPWCCtM(TextPainter.kt:226)
                                                                                                    	at androidx.compose.ui.text.TextPainterKt.drawText-TPWCCtM$default(TextPainter.kt:208)
r
What's your
max
when you compute
canvasHeight
(also, what does
measureHeight
do?)
Looking at the implementation of
drawText
I don't see what could cause this exception to happen unless there's something really weird about the size of the
Spacer
in your example
b
right now
max
is
200.dp
,
measureHeight
estimates how high the actual drawing will be (in
dp
), so that i can set the size of the canvas to shorter than max if it's less than 200 (shrink to fit content)
the size is max when i get the exception
so 200dp
r
Could you print this out please?
java.lang.Math.round(ceil(canvasHeight.toPx() - 540f)).coerceAtLeast(0)
(when the issue happens)
(or drop the
toPx()
if your height is already in pixels)
b
canvasHeight
is
182.dp
(364.0 px), so your line is printing 0
r
as expected
so I don't get why the code crashes 😕
b
yea i dont understand, seems to be something inside the text handling
r
The line I gave you is what computes the values that seem to cause the crash
in your case
size
is
Unspecified
, so it should set
min/maxHeight
to
0
which satisfies the condition in
Constraints
b
Yea i'm not sure where it's getting the numbers, last week when I was looking into the issue I was seeing the same exception thrown in the AS preview window, and it said (i believe minHeight) was negative. today i updated to the latest compose bom and updated my agp dependencies and now the preview isn't working anymore
actually if i dig into the code, the function in my cache doesn't have the
coerceAtLeast
Copy code
if (isHeightNaN) {
        minHeight = 0
        maxHeight = ceil(this.size.height - topLeft.y).fastRoundToInt()
    } else {
        val fixedHeight = ceil(size.height).fastRoundToInt()
        minHeight = fixedHeight
        maxHeight = fixedHeight
    }
r
aaah
which version of Compose are you on?
b
compose-bom = "2025.09.01"
r
Looks like you'll have to wait for a new version of Compose, or do a bounds check yourself 😕
The alternative would be to use the
nativeCanvas
on Android and uses drawText there, which won't have this issue
b
yea i don't think i need the bounds check at all (i'm not trying to fit it within the canvas size), so it doesn't need to do any wrapping or multi-line stuff, can i just tell it to ignore constrains?
r
Not that I can see. Which is why I mentioned
nativeCanvas.drawText()
which won't do wrapping/multi-line
(but Android specific, etc.)
b
thats fine, this is very android specific
👍 1
i could also just pass it a fake size, looks like that's only used to check that constraint
so it seems to be working now, thanks. if only my compose preview didn't break with the version update 😞