Scrollen

Modifikatoren für das Scrollen

Die Modifikatoren verticalScroll und horizontalScroll sind die einfachste Möglichkeit, dem Nutzer das Scrollen eines Elements zu ermöglichen, wenn dessen Inhalt größer ist als seine maximale Größe. Mit den Modifikatoren verticalScroll und horizontalScroll müssen Sie den Inhalt weder übersetzen noch verschieben.

@Composable
private fun ScrollBoxes() {
    Column(
        modifier = Modifier
            .background(Color.LightGray)
            .size(100.dp)
            .verticalScroll(rememberScrollState())
    ) {
        repeat(10) {
            Text("Item $it", modifier = Modifier.padding(2.dp))
        }
    }
}

Eine einfache vertikale Liste,
die auf Scroll-Gesten reagiert,

Mit ScrollState können Sie die Scrollposition ändern oder ihren aktuellen Status abrufen. Zum Erstellen mit Standardparametern verwenden Sie rememberScrollState().

@Composable
private fun ScrollBoxesSmooth() {
    // Smoothly scroll 100px on first composition
    val state = rememberScrollState()
    LaunchedEffect(Unit) { state.animateScrollTo(100) }

    Column(
        modifier = Modifier
            .background(Color.LightGray)
            .size(100.dp)
            .padding(horizontal = 8.dp)
            .verticalScroll(state)
    ) {
        repeat(10) {
            Text("Item $it", modifier = Modifier.padding(2.dp))
        }
    }
}

Scrollbarer Modifikator

Der scrollable-Modifikator unterscheidet sich insofern von den Scroll-Modifikatoren, dass scrollable die Scrollbewegungen erkennt und die Deltas erfasst, seinen Inhalt aber nicht automatisch versetzt. Dies wird stattdessen über ScrollableState an den Nutzer delegiert, der erforderlich ist, damit dieser Modifikator korrekt funktioniert.

Beim Erstellen von ScrollableState musst du eine consumeScrollDelta-Funktion bereitstellen, die bei jedem Scrollschritt (durch Gesteneingabe, gleichmäßiges Scrollen oder Wischen) mit dem Delta in Pixeln aufgerufen wird. Diese Funktion muss die verbrauchte Scrollstrecke zurückgeben, damit das Ereignis richtig weitergegeben wird, wenn es verschachtelte Elemente mit dem Modifikator scrollable gibt.

Das folgende Snippet erkennt die Touch-Gesten und zeigt einen numerischen Wert für einen Versatz an, aber platziert keine Elemente:

@Composable
private fun ScrollableSample() {
    // actual composable state
    var offset by remember { mutableStateOf(0f) }
    Box(
        Modifier
            .size(150.dp)
            .scrollable(
                orientation = Orientation.Vertical,
                // Scrollable state: describes how to consume
                // scrolling delta and update offset
                state = rememberScrollableState { delta ->
                    offset += delta
                    delta
                }
            )
            .background(Color.LightGray),
        contentAlignment = Alignment.Center
    ) {
        Text(offset.toString())
    }
}

Ein UI-Element, das den Fingerdruck erkennt und den numerischen Wert für die Position des Fingers anzeigt

Verschachteltes Scrollen

Verschachteltes Scrollen ist ein System, bei dem mehrere ineinander enthaltene Scrolling-Komponenten zusammenarbeiten, indem sie auf eine einzelne Scroll-Geste reagieren und ihre Scrolldeltas (Änderungen) kommunizieren.

Das verschachtelte Scrolling-System ermöglicht die Koordination zwischen Komponenten, die scrollbar und hierarchisch verknüpft sind (meist durch gemeinsames übergeordnetes Element). Dieses System verknüpft scrollbare Container und ermöglicht eine Interaktion mit den Scrolldeltas, die weitergegeben und untereinander geteilt werden.

Mit der Funktion „Compose“ haben Sie mehrere Möglichkeiten, verschachteltes Scrollen zwischen zusammensetzbaren Funktionen zu verarbeiten. Ein typisches Beispiel für verschachteltes Scrollen ist eine Liste innerhalb einer anderen Liste. Ein komplexeres Beispiel ist die Minimierbare Symbolleiste.

Automatisches verschachteltes Scrollen

Beim einfachen verschachtelten Scrollen müssen Sie nichts weiter tun. Gesten, die eine Scrollaktion auslösen, werden automatisch von untergeordneten Elementen an übergeordnete Elemente weitergegeben. Wenn das untergeordnete Element also nicht weiterscrollen kann, wird die Geste vom übergeordneten Element verarbeitet.

Automatisch verschachteltes Scrollen wird von einigen Komponenten und Modifikatoren von Composer unterstützt und standardmäßig bereitgestellt: verticalScroll, horizontalScroll, scrollable, Lazy APIs und TextField. Wenn der Nutzer also durch ein untergeordnetes untergeordnetes Element von verschachtelten Komponenten scrollt, leiten die vorherigen Modifikatoren die Scroll-Deltas an die übergeordneten Elemente weiter, die verschachteltes Scrollen unterstützen.

Im folgenden Beispiel werden Elemente mit einem verticalScroll-Modifikator in einem Container gezeigt, auf den auch ein verticalScroll-Modifikator angewendet wird.

@Composable
private fun AutomaticNestedScroll() {
    val gradient = Brush.verticalGradient(0f to Color.Gray, 1000f to Color.White)
    Box(
        modifier = Modifier
            .background(Color.LightGray)
            .verticalScroll(rememberScrollState())
            .padding(32.dp)
    ) {
        Column {
            repeat(6) {
                Box(
                    modifier = Modifier
                        .height(128.dp)
                        .verticalScroll(rememberScrollState())
                ) {
                    Text(
                        "Scroll here",
                        modifier = Modifier
                            .border(12.dp, Color.DarkGray)
                            .background(brush = gradient)
                            .padding(24.dp)
                            .height(150.dp)
                    )
                }
            }
        }
    }
}

Zwei verschachtelte vertikale Scrolling-UI-Elemente, die auf Gesten innerhalb und außerhalb des inneren Elements reagieren

Den nestedScroll-Modifikator verwenden

Wenn Sie ein erweitertes koordiniertes Scrollen zwischen mehreren Elementen erstellen müssen, bietet der Modifikator nestedScroll mehr Flexibilität, da eine verschachtelte Scrollhierarchie definiert wird. Wie im vorherigen Abschnitt erwähnt, bieten einige Komponenten integrierte Unterstützung für verschachteltes Scrollen. Bei zusammensetzbaren Funktionen, die nicht automatisch scrollbar sind, wie Box oder Column, werden Scroll-Deltas bei solchen Komponenten jedoch im verschachtelten Scroll-System nicht weitergegeben und die Deltas erreichen weder die NestedScrollConnection noch die übergeordnete Komponente. Sie können dieses Problem beheben, indem Sie nestedScroll verwenden, um anderen Komponenten, einschließlich benutzerdefinierter Komponenten, eine solche Unterstützung zu bieten.

Verschachtelter Scrollzyklus

Der verschachtelte Scrollzyklus ist der Fluss von Scrolldeltas, die im Hierarchiebaum nach oben und unten durch alle Komponenten (oder Knoten) ausgelöst werden, die Teil des verschachtelten Scrollingsystems sind, z. B. mithilfe von scrollbaren Komponenten und Modifikatoren oder nestedScroll.

Phasen des verschachtelten Scrollzyklus

Wenn ein Triggerereignis (z. B. eine Geste) von einer scrollbaren Komponente erkannt wird, bevor die eigentliche Scrollaktion ausgelöst wird, werden die generierten Deltas an das verschachtelte Scrollsystem gesendet und durchlaufen drei Phasen: Pre-Scrolling, Knotenverbrauch und Post-Scrollen.

Die Phasen des verschachtelten
Scrollzyklus

In der ersten Pre-Scrolling-Phase löst die Komponente, die die Triggerereignis-Deltas empfangen hat, diese Ereignisse über den Hierarchiebaum nach oben zum obersten übergeordneten Element aus. Die Delta-Ereignisse werden dann nach unten geleitet, was bedeutet, dass Deltas vom Stamm mit dem obersten übergeordneten Element nach unten zum untergeordneten Element übertragen werden, das den verschachtelten Scroll-Zyklus gestartet hat.

Pre-Scrolling-Phase: Weiterleitung nach oben

Dadurch haben die verschachtelten übergeordneten Scroll-Elemente (zusammensetzbare Funktionen mit nestedScroll oder scrollbaren Modifikatoren) die Möglichkeit, das Delta zu verwenden, bevor der Knoten es selbst verarbeiten kann.

Pre-Scrolling-Phase – Bubbling Down

In der Phase der Knotennutzung verwendet der Knoten selbst das Delta, das von seinen übergeordneten Elementen nicht verwendet wurde. Dies ist der Zeitpunkt, an dem das Scrollen tatsächlich abgeschlossen ist und sichtbar ist.

Phase des Knotenverbrauchs

Während dieser Phase kann das untergeordnete Element entscheiden, den verbleibenden Scrollvorgang vollständig oder teilweise aufzubrauchen. Alles, was übrig ist, wird wieder nach oben gesendet, um die Post-Scroll-Phase zu durchlaufen.

In der Post-Scroll-Phase wird alles, was der Knoten selbst nicht verarbeitet hat, noch einmal an seine Ancestors gesendet.

Post-Scrolling-Phase:
Weiterleitung nach oben

Die Post-Scroll-Phase funktioniert ähnlich wie die Pre-Scroll-Phase, bei der die übergeordneten Elemente entscheiden, ob sie Inhalte verbrauchen oder nicht.

Post-Scrolling-Phase:
Bubbling Down

Ähnlich wie beim Scrollen kann die Absicht des Nutzers nach dem Ende einer Ziehgeste in eine Geschwindigkeit umgewandelt werden, mit der der scrollbare Container geflogen wird (Scrollen mit einer Animation). Das Fling ist ebenfalls Teil des verschachtelten Scroll-Zyklus und die durch das Drag-Ereignis erzeugten Geschwindigkeiten durchlaufen ähnliche Phasen: Vor-Fling, Knotenverbrauch und Nach-Feing. Beachten Sie, dass die Fling-Animation nur mit Touch-Gesten verknüpft ist und nicht durch andere Ereignisse ausgelöst wird, z. B. durch Scrollen oder Scrollen auf der Hardware.

Am verschachtelten Scroll-Zyklus teilnehmen

Teilnahme am Zyklus bedeutet, dass der Konsum von Deltas entlang der Hierarchie abgefangen, verbraucht und gemeldet wird. Compose bietet eine Reihe von Tools, die beeinflussen, wie das verschachtelte Scrolling-System funktioniert und wie direkt damit interagiert werden kann, z. B. wenn Sie etwas mit den Scrolldeltas bearbeiten müssen, bevor eine scrollbare Komponente überhaupt scrollt.

Wenn es sich beim verschachtelten Scrollzyklus um ein System handelt, das auf eine Knotenkette wirkt, können diese Änderungen mit dem Modifikator nestedScroll abgefangen und in diese eingefügt sowie die in der Kette weitergegebenen Daten (Scroll-Deltas) beeinflusst werden. Dieser Modifikator kann an einer beliebigen Stelle in der Hierarchie platziert werden und kommuniziert mit verschachtelten Scrollmodifikatorinstanzen in der Baumstruktur, damit er Informationen über diesen Kanal teilen kann. Die Bausteine dieses Modifikators sind NestedScrollConnection und NestedScrollDispatcher.

NestedScrollConnection bietet eine Möglichkeit, auf die Phasen des verschachtelten Scrollzyklus zu reagieren und das verschachtelte Scrollsystem zu beeinflussen. Sie besteht aus vier Callback-Methoden, die jeweils eine der Phasen des Verbrauchs darstellen: Pre/Post-Scrolling und Pre/Post-fling:

val nestedScrollConnection = object : NestedScrollConnection {
    override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
        println("Received onPreScroll callback.")
        return Offset.Zero
    }

    override fun onPostScroll(
        consumed: Offset,
        available: Offset,
        source: NestedScrollSource
    ): Offset {
        println("Received onPostScroll callback.")
        return Offset.Zero
    }
}

Jeder Callback enthält auch Informationen über das weitergegebene Delta: das Delta available für diese bestimmte Phase und das in den vorherigen Phasen verwendete consumed-Delta. Wenn Sie die Weitergabe von Deltas in der Hierarchie an einem beliebigen Punkt beenden möchten, können Sie dazu die verschachtelte Scroll-Verbindung verwenden:

val disabledNestedScrollConnection = remember {
    object : NestedScrollConnection {
        override fun onPostScroll(
            consumed: Offset,
            available: Offset,
            source: NestedScrollSource
        ): Offset {
            return if (source == NestedScrollSource.SideEffect) {
                available
            } else {
                Offset.Zero
            }
        }
    }
}

Alle Callbacks liefern Informationen zum Typ NestedScrollSource.

NestedScrollDispatcher initialisiert den verschachtelten Scrollzyklus. Durch die Verwendung eines Disponenten und das Aufrufen seiner Methoden wird der Zyklus ausgelöst. Scrollbare Container haben einen integrierten Disponenten, der Deltas, die während Gesten erfasst wurden, an das System sendet. Aus diesem Grund wird in den meisten Anwendungsfällen zum Anpassen des verschachtelten Scrollens NestedScrollConnection anstelle eines Disponenten verwendet, um auf bereits vorhandene Deltas zu reagieren, anstatt neue zu senden. Weitere Verwendungen finden Sie unter NestedScrollDispatcherSample.

Verschachtelte Scroll-Interoperabilität

Wenn Sie scrollbare View-Elemente in scrollbaren zusammensetzbaren Funktionen verschachteln oder umgekehrt, können Probleme auftreten. Die auffälligsten treten auf, wenn Sie durch das untergeordnete Element scrollen, seine Start- oder Endgrenzen erreichen und erwarten, dass das übergeordnete Element das Scrollen übernimmt. Dieses erwartete Verhalten kann jedoch entweder nicht eintreten oder nicht wie erwartet funktionieren.

Dieses Problem ist auf die Erwartungen zurückzuführen, die von den Funktionen für scrollbare zusammensetzbare Funktionen erfüllt wurden. Zusammensetzbare Funktionen mit Scrollen haben eine Standardregel für verschachteltes Scrollen. Das bedeutet, dass jeder scrollbare Container an der verschachtelten Scroll-Kette teilnehmen muss, sowohl als übergeordneter Container über NestedScrollConnection als auch als untergeordneter Container über NestedScrollDispatcher. Das untergeordnete Element führt dann ein verschachteltes Scrollen für das übergeordnete Element aus, wenn sich das untergeordnete Element an der Grenze befindet. Diese Regel sorgt beispielsweise dafür, dass die Optionen „Compose“ (Pager) und „Compose“ (LazyRow) gut zusammen funktionieren. Wenn jedoch mit ViewPager2 oder RecyclerView gescrollt wird, weil NestedScrollingParent3 nicht implementiert ist, ist kein kontinuierliches Scrollen von einem untergeordneten zum übergeordneten Element möglich.

Wenn Sie die verschachtelte Scrolling Interop API zwischen scrollbaren View-Elementen und scrollbaren zusammensetzbaren Funktionen aktivieren möchten, die in beide Richtungen verschachtelt sind, können Sie in den folgenden Szenarien die verschachtelte Scrolling Interop API verwenden, um diese Probleme zu beheben.

Ein kooperierendes übergeordnetes Element View mit einem untergeordneten ComposeView

Eine kooperative übergeordnete View ist eine, die NestedScrollingParent3 bereits implementiert und daher Scroll-Deltas von einer kooperativen verschachtelten untergeordneten zusammensetzbaren Funktion erhalten kann. ComposeView würde in diesem Fall als untergeordnetes Objekt fungieren und müsste (indirekt) NestedScrollingChild3 implementieren. Ein Beispiel für ein kooperatives Elternteil ist androidx.coordinatorlayout.widget.CoordinatorLayout.

Wenn Sie verschachtelte Scrolling-Interoperabilität zwischen übergeordneten View-Containern und verschachtelten scrollbaren untergeordneten zusammensetzbaren Funktionen benötigen, können Sie rememberNestedScrollInteropConnection() verwenden.

rememberNestedScrollInteropConnection() ermöglicht und merkt sich die NestedScrollConnection, die die verschachtelte Scroll-Interoperabilität zwischen einem übergeordneten View-Element, das NestedScrollingParent3 implementiert, und einem untergeordneten Element vom Typ „Schreiben“ ermöglicht. Er sollte in Verbindung mit einem nestedScroll-Modifikator verwendet werden. Da das verschachtelte Scrollen auf der Seite „Schreiben“ standardmäßig aktiviert ist, können Sie über diese Verbindung sowohl das verschachtelte Scrollen auf der Seite View aktivieren als auch die erforderliche Kleblogik zwischen Views und zusammensetzbaren Funktionen einfügen.

Ein häufiger Anwendungsfall ist die Verwendung von CoordinatorLayout, CollapsingToolbarLayout und einer untergeordneten zusammensetzbaren Funktion, wie in diesem Beispiel:

<androidx.coordinatorlayout.widget.CoordinatorLayout
    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">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:fitsSystemWindows="true">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <!--...-->

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/compose_view"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Richten Sie in der Aktivität oder dem Fragment die zusammensetzbare Funktion Ihres untergeordneten Elements und die erforderliche NestedScrollConnection ein:

open class MainActivity : ComponentActivity() {
    @OptIn(ExperimentalComposeUiApi::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<ComposeView>(R.id.compose_view).apply {
            setContent {
                val nestedScrollInterop = rememberNestedScrollInteropConnection()
                // Add the nested scroll connection to your top level @Composable element
                // using the nestedScroll modifier.
                LazyColumn(modifier = Modifier.nestedScroll(nestedScrollInterop)) {
                    items(20) { item ->
                        Box(
                            modifier = Modifier
                                .padding(16.dp)
                                .height(56.dp)
                                .fillMaxWidth()
                                .background(Color.Gray),
                            contentAlignment = Alignment.Center
                        ) {
                            Text(item.toString())
                        }
                    }
                }
            }
        }
    }
}

Eine zusammensetzbare übergeordnete Funktion mit einem untergeordneten AndroidView

In diesem Szenario wird die Implementierung der verschachtelten Scrolling-Interop API auf der Erstellungsseite behandelt, wenn Sie eine übergeordnete zusammensetzbare Funktion mit einem untergeordneten AndroidView haben. Der AndroidView implementiert NestedScrollDispatcher, da er einem übergeordneten übergeordneten Element des Typs „Compose“ als untergeordnetes Element dient und NestedScrollingParent3, da es als übergeordnetes Element für ein untergeordnetes View-Scrollen fungiert. Das übergeordnete Element kann dann verschachtelte Scroll-Deltas von einem verschachtelten scrollbaren untergeordneten View erhalten.

Das folgende Beispiel zeigt, wie Sie in diesem Szenario eine verschachtelte Scroll-Interop zusammen mit einer minimierbaren Symbolleiste zum Schreiben erstellen können:

@Composable
private fun NestedScrollInteropComposeParentWithAndroidChildExample() {
    val toolbarHeightPx = with(LocalDensity.current) { ToolbarHeight.roundToPx().toFloat() }
    val toolbarOffsetHeightPx = remember { mutableStateOf(0f) }

    // Sets up the nested scroll connection between the Box composable parent
    // and the child AndroidView containing the RecyclerView
    val nestedScrollConnection = remember {
        object : NestedScrollConnection {
            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
                // Updates the toolbar offset based on the scroll to enable
                // collapsible behaviour
                val delta = available.y
                val newOffset = toolbarOffsetHeightPx.value + delta
                toolbarOffsetHeightPx.value = newOffset.coerceIn(-toolbarHeightPx, 0f)
                return Offset.Zero
            }
        }
    }

    Box(
        Modifier
            .fillMaxSize()
            .nestedScroll(nestedScrollConnection)
    ) {
        TopAppBar(
            modifier = Modifier
                .height(ToolbarHeight)
                .offset { IntOffset(x = 0, y = toolbarOffsetHeightPx.value.roundToInt()) }
        )

        AndroidView(
            { context ->
                LayoutInflater.from(context)
                    .inflate(R.layout.view_in_compose_nested_scroll_interop, null).apply {
                        with(findViewById<RecyclerView>(R.id.main_list)) {
                            layoutManager = LinearLayoutManager(context, VERTICAL, false)
                            adapter = NestedScrollInteropAdapter()
                        }
                    }.also {
                        // Nested scrolling interop is enabled when
                        // nested scroll is enabled for the root View
                        ViewCompat.setNestedScrollingEnabled(it, true)
                    }
            },
            // ...
        )
    }
}

private class NestedScrollInteropAdapter :
    Adapter<NestedScrollInteropAdapter.NestedScrollInteropViewHolder>() {
    val items = (1..10).map { it.toString() }

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): NestedScrollInteropViewHolder {
        return NestedScrollInteropViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.list_item, parent, false)
        )
    }

    override fun onBindViewHolder(holder: NestedScrollInteropViewHolder, position: Int) {
        // ...
    }

    class NestedScrollInteropViewHolder(view: View) : ViewHolder(view) {
        fun bind(item: String) {
            // ...
        }
    }
    // ...
}

Dieses Beispiel zeigt, wie Sie die API mit einem scrollable-Modifikator verwenden können:

@Composable
fun ViewInComposeNestedScrollInteropExample() {
    Box(
        Modifier
            .fillMaxSize()
            .scrollable(rememberScrollableState {
                // View component deltas should be reflected in Compose
                // components that participate in nested scrolling
                it
            }, Orientation.Vertical)
    ) {
        AndroidView(
            { context ->
                LayoutInflater.from(context)
                    .inflate(android.R.layout.list_item, null)
                    .apply {
                        // Nested scrolling interop is enabled when
                        // nested scroll is enabled for the root View
                        ViewCompat.setNestedScrollingEnabled(this, true)
                    }
            }
        )
    }
}

Und schließlich zeigt dieses Beispiel, wie die verschachtelte Scrolling-Interop API mit BottomSheetDialogFragment verwendet wird, um ein Drag-and-drop-Verhalten zu erzielen:

class BottomSheetFragment : BottomSheetDialogFragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val rootView: View = inflater.inflate(R.layout.fragment_bottom_sheet, container, false)

        rootView.findViewById<ComposeView>(R.id.compose_view).apply {
            setContent {
                val nestedScrollInterop = rememberNestedScrollInteropConnection()
                LazyColumn(
                    Modifier
                        .nestedScroll(nestedScrollInterop)
                        .fillMaxSize()
                ) {
                    item {
                        Text(text = "Bottom sheet title")
                    }
                    items(10) {
                        Text(
                            text = "List item number $it",
                            modifier = Modifier.fillMaxWidth()
                        )
                    }
                }
            }
            return rootView
        }
    }
}

Durch rememberNestedScrollInteropConnection() wird ein NestedScrollConnection-Element in dem Element installiert, an das Sie es anhängen. NestedScrollConnection überträgt die Deltas von der Erstellungsebene an die View-Ebene. Dadurch kann das Element an verschachteltem Scrollen teilnehmen, das automatische Scrollen von Elementen wird jedoch nicht automatisch aktiviert. Bei zusammensetzbaren Funktionen, die nicht automatisch scrollbar sind, wie Box oder Column, werden Scroll-Deltas bei solchen Komponenten im verschachtelten Scroll-System nicht weitergegeben und die Deltas erreichen nicht den von rememberNestedScrollInteropConnection() bereitgestellten NestedScrollConnection. Daher erreichen diese Deltas nicht die übergeordnete Komponente View. Um dieses Problem zu beheben, müssen Sie auch scrollbare Modifikatoren für diese Typen von verschachtelten zusammensetzbaren Funktionen festlegen. Weitere Informationen findest du im vorherigen Abschnitt zum verschachtelten Scrollen.

Ein nicht kooperierendes übergeordnetes Element View mit einem untergeordneten ComposeView

Eine nicht kooperative Ansicht ist eine Ansicht, die nicht die erforderlichen NestedScrolling-Schnittstellen auf der View-Seite implementiert. Das bedeutet, dass die verschachtelte Scroll-Interoperabilität mit diesen Views nicht von Anfang an funktioniert. Nicht kooperierende Views sind RecyclerView und ViewPager2.