Status Update
Comments
em...@gmail.com <em...@gmail.com> #2
Some notes from digging into this a bit:
- unexpected wrapping doesn't start until a TextView that line wraps runs it's line breaking logic.
- style doesn't seem to matter, so long as the line breaker is ran.
- Moving the
TextView
below the compose view so that it runs first makes the first draw not wrap in the compose text. Subsequent re-measures will start wrapping. - This may require a
StaticLayout
to run inTextView
beforeStaticLayout
runs inText
(BoringLayout
doesn't seem to cause this, but that doesn't have line breaking by definition), but I'm not certain.
- Inputs to
LineBreaker.computeLineBreaks
seem to have consistent arguments for repro and non-repro use cases. - Couldn't run in demo app, so the layouts/views may also be necessary to repro.
- Used a API 35 Pixel 9 Pro XL emulator to repro. Verified that using API 34 does not repro.
- Moving the
TextView
from the layout to anAndroidView
in ourComposeView
still repros.
jb...@google.com <jb...@google.com> #3
Able to repro from a blank project with only activity-compose, compose foundation, and the font files.
- Create new blank compose project. (should be target api 35 already)
- Replace
dependencies
inapp/build.gradle.kts
with the below and sync the dependencies. - Delete the
ui
source dirs (all the material related stuff). - Copy the font files from the
reprod.zip
in the description of this bug into the new project. - Replace the
MainActivity
file with the below code. - Run the app on a Pixel 9 Pro XL - API 35 emulator.
dependencies {
implementation("androidx.activity:activity-compose:1.10.0")
implementation("androidx.compose.foundation:foundation:1.7.6")
}
import android.os.Bundle
import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent { Content() }
}
}
private val ReproFontFamily =
FontFamily(
Font(R.font.noto_ikea_latin_regular, FontWeight.Normal),
Font(R.font.noto_ikea_latin_bold, FontWeight.Bold)
)
@Composable
private fun Content() {
Column(
modifier = Modifier
.safeContentPadding()
.fillMaxWidth()
.padding(32.dp)
) {
AndroidView(factory = { ctx -> TextView(ctx).apply { text = "Line1\nLine2" } })
BasicText(
text = "ALEX",
style = TextStyle(
fontWeight = FontWeight.Bold,
color = Color.Black,
fontFamily = ReproFontFamily,
fontSize = 14.sp,
lineHeight = 22.sp,
),
modifier = Modifier.background(Color.Magenta),
)
}
}
em...@gmail.com <em...@gmail.com> #4
This actually does work in the demo app, I just forgot to change the target api. See
jb...@google.com <jb...@google.com> #5
Maybe related, but not convinced:
si...@gmail.com <si...@gmail.com> #6
Nona, can you take a look?
jb...@google.com <jb...@google.com> #7
fontSize = 12.sp
fontWeight = SemiBold
letterSpacing = 0
lineHeights = 16.sp
me...@gmail.com <me...@gmail.com> #8
em...@gmail.com <em...@gmail.com> #9
I don't recommend this, but if you really need a workaround right now, here it is. This is probably quite brittle, slow, and I have not tested it other than checking that it does fix the bug. Use at your own risk. The actual fix for this is expected in 1.8.0-beta02
.
A very hacky workaround would be adding this modifier to the end of your Text
's modifier chain:
/** Intercept pre-layout to manually recycle `StaticLayout.Builder.useBoundsForWidth`. */
private fun Modifier.unexpectedTextWrappingWorkaround(): Modifier =
layout { measurable, constraints ->
if (Build.VERSION.SDK_INT >= 35) {
Api35Helper.resetStaticLayoutBuilderUseBoundsForWidth()
}
val placeable = measurable.measure(constraints)
layout(placeable.width, placeable.height) { placeable.place(0, 0) }
}
@RequiresApi(35)
private object Api35Helper {
@JvmStatic
fun resetStaticLayoutBuilderUseBoundsForWidth() {
StaticLayout.Builder.obtain("a", 0, 1, TextPaint(), 1024)
.setUseBoundsForWidth(false)
.build() // recycles the StaticLayout.
}
}
da...@gmail.com <da...@gmail.com> #10
Project: platform/frameworks/support
Branch: androidx-main
Author: Seigo Nonaka <
Link:
Fix unexpected enabling of useBoundsForWidth
Expand for full commit details
Fix unexpected enabling of useBoundsForWidth
This fixes a bug where a text may wrap to a second line where it is unnecessary.
Bug: 391378120
Test: Manual tests to ensure the unexpected wrapping stops after the fix is applied
Test: StaticLayoutFactoryTest#create_useBoundsForWidth_disabled
Test: BasicTextUnexpectedWrappingRegressionTest
Change-Id: I1b40c5816f2b4c1e787de05d5332db6fc0efad14
Files:
- A
compose/foundation/foundation/src/androidInstrumentedTest/assets/font/overshoot_test.ttx
- A
compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/BasicTextUnexpectedWrappingRegressionTest.kt
- A
compose/foundation/foundation/src/androidInstrumentedTest/res/font/overshoot_test.ttf
- M
compose/ui/ui-text/src/androidInstrumentedTest/kotlin/androidx/compose/ui/text/android/StaticLayoutFactoryTest.kt
- M
compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/android/StaticLayoutFactory.android.kt
Hash: 7d19be04e9c2af237f0605a148605bf52f607497
Date: Thu Jan 23 17:40:54 2025
il...@google.com <il...@google.com> #11
si...@gmail.com <si...@gmail.com> #12
This will be targeting 1.8
, likely landing in beta02
.
1.7.*
targets android API 34, and this fix requires API 35. Upgrading 1.7
to android api 35 is too large of a change for a 1.7.x
version.
sa...@gmail.com <sa...@gmail.com> #13
Separate note, an upstream fix in the android platform is expected in api level 36, so this issue should only occur when API level is 35 and compose version is below 1.8.
jb...@google.com <jb...@google.com>
cl...@google.com <cl...@google.com> #14
Saw that beta02
is out but there is no mention of this issue being fixed in the release notes. Were you able to land the fix in beta02 or it got pushed to a future version?
ap...@google.com <ap...@google.com> #15
Looks like it actually went out in beta01
.
cl...@google.com <cl...@google.com> #16
Do you have some kind of ETA when 1.8 will reach stable?
We're currently debating on switching our prod app on the compose-bom-beta:2025.02.00
artifact otherwise which points to 1.8.0-beta02
versions at the moment.
da...@gmail.com <da...@gmail.com> #17
The team just release 1.8.0-rc01 compose-bom-beta:2025.03.00
and I am still seeing the issue happen inconsistently.
cl...@google.com <cl...@google.com> #18
Typo - it is available in navigation-2.9.0-alpha04
.
te...@gmail.com <te...@gmail.com> #19
pr...@google.com <pr...@google.com> #20
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.navigation:navigation-common:2.9.0-alpha04
da...@gmail.com <da...@gmail.com> #21
I've tested with the proposed fix and can confirm this is resolved for me.
Description
Version used: 2.8.0
Devices/Android versions reproduced on: Android 11
Previous working version: 2.7.7
Using Navigation 2.7.7 all works fine but when updating to 2.8.0 I get "error: cannot access KSerializer" ("class file for kotlinx.serialization.KSerializer not found") at this line:
- navGraph.(HERE IS THE MARKED POINT)setStartDestination(R.id.nav_permissions)
during "Task :app:compileDebugJavaWithJavac".
This piece of code placed in a MainActivity.onCreate() method:
- NavGraph navGraph = navController.getGraph();
- navGraph.setStartDestination(R.id.nav_permissions)
Those are my TOML libraries versions used in this project:
annotation = "1.8.2"
appcompat = "1.7.0"
constraintlayout = "2.1.4"
flexbox = "3.0.0"
gradle_plugin = "8.6.0"
kotlin = "1.9.24"
livedata = "2.8.5"
material = "1.12.0"
navigation = "2.8.0" (<-- returning to 2.7.7 solves this issue)
preference = "1.2.1"
sdk_compile = "34"
sdk_target = "33"
volley = "1.2.1"
Unfortunately the project is very big and I'm unable to cleanup to create a simple sample project for replicate this error.
I hope it would be enough those info.....