Crash on ReadMoreText with IntrinsicSize
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 54/100
Direzione di ricerca
Start in the CoreReadMoreText implementation and trace how BoxWithConstraints supplies the width used to calculate collapsed text. The proposal identifies replacing it with Box, recording width from BasicText's onTextLayout, and recalculating collapsed text; check the foundation, material, and material3 tests, including intrinsic-height measurement and width changes. Done means intrinsic measurement no longer crashes and the collapsed text updates correctly without public API changes.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Problem
ReadMoreText crashes when its parent asks for intrinsic measurements, for example Row(Modifier.height(IntrinsicSize.Max)). This applies to BasicReadMoreText and to the material and material3 wrappers.
java.lang.IllegalStateException: Asking for intrinsic measurements of SubcomposeLayout layouts is not supported. This includes components that are built on top of SubcomposeLayout, such as lazy lists, BoxWithConstraints, TabRow, etc. To mitigate this:
Since 1.7.0 (#93), CoreReadMoreText wraps BasicText in BoxWithConstraints to read constraints.maxWidth for TextMeasurer. BoxWithConstraints is built on SubcomposeLayout, which does not support intrinsic measurements.
A common case is a horizontal carousel whose cards all match the tallest one:
Row(
modifier = Modifier
.horizontalScroll(rememberScrollState())
.height(IntrinsicSize.Max),
) {
posts.forEach { post ->
Column(Modifier.width(292.dp).fillMaxHeight()) {
ReadMoreText(
text = post.body,
expanded = false,
readMoreText = "more",
readMoreMaxLines = 3,
)
}
}
}
Proposal
BoxWithConstraints is only used for constraints.maxWidth. BasicText already reports the same value through onTextLayout (TextLayoutResult.layoutInput.constraints), and onTextLayout is called only for the real layout, not for intrinsic measurements.
- Replace
BoxWithConstraintswithBox. - Keep
maxWidthin a state and update it fromonTextLayout. - Compute the collapsed text with
remember(maxWidth, ...)instead ofLaunchedEffect.ReadMoreState.applyCollapsedText()becomescalculateCollapsedText(), which returns the collapsed text. Its body stays the same.
The collapsed text is still measured from the original text with TextMeasurer. Only the width source changes. No public API changes.
val textMeasurer = rememberTextMeasurer()
- val state = remember { ReadMoreState() }
+ var maxWidth by remember { mutableIntStateOf(UnknownWidth) }
+ val collapsedText = remember(
+ textMeasurer,
+ maxWidth,
+ overflowText,
+ readMoreTextWithStyle,
+ style,
+ readMoreStyle,
+ text,
+ readMoreMaxLines,
+ softWrap,
+ inlineContent,
+ ) {
+ if (maxWidth == UnknownWidth) {
+ AnnotatedString("")
+ } else {
+ calculateCollapsedText(
+ textMeasurer = textMeasurer,
+ constraints = Constraints(maxWidth = maxWidth),
+ overflowText = overflowText,
+ readMoreTextWithStyle = readMoreTextWithStyle,
+ style = style,
+ readMoreStyle = readMoreStyle,
+ text = text,
+ readMoreMaxLines = readMoreMaxLines,
+ softWrap = softWrap,
+ inlineContent = inlineContent,
+ )
+ }
+ }
+ val isCollapsible = collapsedText.isNotEmpty()
...
- BoxWithConstraints(
+ Box(
modifier = modifier
.then(toggleableModifier)
.padding(contentPadding),
) {
BasicText(
text = currentText,
modifier = Modifier,
style = style,
- onTextLayout = onTextLayout,
+ onTextLayout = { result ->
+ maxWidth = result.layoutInput.constraints.maxWidth
+ onTextLayout(result)
+ },
overflow = TextOverflow.Ellipsis,
softWrap = softWrap,
maxLines = if (expanded) Int.MAX_VALUE else readMoreMaxLines,
inlineContent = inlineContent,
)
-
- val constraints = Constraints(maxWidth = constraints.maxWidth)
- LaunchedEffect(
- ...
- ) {
- state.applyCollapsedText(...)
- }
}
Checked with a local prototype
verifyRoborazziDebugpasses forreadmore-foundation,readmore-materialandreadmore-material3(168 cases) with no image changes.- In
Row(Modifier.height(IntrinsicSize.Max))it no longer crashes, and the last line ends with… more. - When the width changes from 300dp to 200dp and then to 320dp, the collapsed text is recalculated each time.
- Frame timing is the same as now. The first frame shows the original text with an ellipsis, and the next frame shows the collapsed text with "more".
Alternatives considered
- Capturing the constraints in
Modifier.layout {}: its measure block also runs for intrinsic queries, so the state would be written during intrinsic passes.onTextLayoutruns only for the real layout. - A custom
Layoutthat measures withTextMeasurerand draws withdrawText(): the collapsed text would be ready in the first frame, but it would lose whatBasicTextprovides, such asLinkAnnotationforToggleArea.More, semantics andinlineContent.
- Lingua principale
- Kotlin
- Stelle
- 209
- Fork
- 14
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di webtoon/ReadMoreTextView
-
Support Kotlin MultiplatformAperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 20/100
webtoon/ReadMoreTextView#57 ·
Tutte le issue di webtoon/ReadMoreTextView
Issue simili
-
bug follow-up
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
binding:web core docs p3
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
RunanywhereAI/runanywhere-sdks#1123 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
openai/openai-java#1202 ·
I maintainer di solito rispondono entro 1 giorno
-
StepExamBenchmarkTest runs a loop and prints a timing but asserts nothingForse già presa Una pull request collegata a questa issue è aperta o già unita. Apertajules
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
open-learning-exchange/myplanet#18199 · 1 commento ·
I maintainer di solito rispondono entro 4 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
auth0/Auth0.Android#1095 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno