Scrollable ComposeView in XML ConstraintLayout: scroll position jumping on state change

63 Views Asked by At

I have a ComposeView that is constrained to another View in an XML ConstraintLayout. The ComposeView houses a Column with VerticalScroll. Whenever you are scrolled to the bottom of the column and change the state of something (eg. toggle a switch), the scroll position jumps to hide the bottom of the column. The jump is equivalent to the height of the view that the ComposeView is constrained to. It does not seem to matter whether it is constrained to the top or bottom of the other view. Has anyone encountered this?

I tried using rememberNestedScrollInteropConnection to no avail.

Here is a mock of the issue to reproduce:

fragment_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/hello"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:background="#12978C"
        android:text="Hello World!"
        android:textAlignment="center"
        app:layout_constraintBottom_toTopOf="@+id/compose"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/compose"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/hello"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

MainFragment.kt

class MainFragment: Fragment() {
    private lateinit var binding: FragmentMainBinding

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) =
        FragmentMainBinding.inflate(
            inflater, container, false
        ).apply {
            binding = this
        }.root

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.compose.setContent {
            val state = remember { List(25) { false }.toMutableStateList() }
                Column(
                    Modifier.verticalScroll(rememberScrollState())
                ) {
                    for (i in 0..24) {
                        Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center) {
                            Text(i.toString(), fontWeight = FontWeight.Bold)
                            Spacer(Modifier.width(15.dp))
                            Switch(state[i], { state[i] = it })
                        }
                    }
                }
        }
    }
}
0

There are 0 best solutions below