Scroll-Modifikatoren
Die Modifikatoren verticalScroll
und horizontalScroll
sind die einfachste Möglichkeit, dem Nutzer das Scrollen eines Elements zu ermöglichen, wenn die Grenzen des Inhalts größer sind als die maximalen Größenbeschränkungen. Mit den Modifikatoren verticalScroll
und horizontalScroll
müssen Sie die Inhalte nicht übersetzen oder versetzen.
@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)) } } }
Mit ScrollState
können Sie die Scrollposition ändern oder den aktuellen Status abrufen. Verwenden Sie zum Erstellen mit Standardparametern 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)) } } }
Scrollable-Modifikator
Der Modifier
scrollable
unterscheidet sich von den Scroll-Modifikatoren dadurch, dass scrollable
die Scroll-Gesten erkennt und die Deltas erfasst, aber den Inhalt nicht automatisch verschiebt. Stattdessen wird die Berechtigung über ScrollableState
an den Nutzer delegiert. Das ist erforderlich, damit der Modifier richtig funktioniert.
Beim Erstellen von ScrollableState
müssen Sie eine consumeScrollDelta
-Funktion angeben, die bei jedem Scrollschritt (durch Gesteneingabe, sanftes Scrollen oder schnelles Wischen) mit dem Delta in Pixeln aufgerufen wird. Diese Funktion muss die zurückgelegte Scrollstrecke zurückgeben, damit das Ereignis richtig weitergegeben wird, wenn verschachtelte Elemente mit dem Modifikator scrollable
vorhanden sind.
Im folgenden Snippet werden die Gesten erkannt und ein numerischer Wert für einen Offset angezeigt, es werden jedoch keine Elemente versetzt:
@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()) } }
Verschachteltes Scrollen
Beim verschachtelten Scrollen reagieren mehrere ineinander verschachtelte Scrollkomponenten auf eine einzelne Scrollbewegung und kommunizieren ihre Scroll-Deltas (Änderungen).
Das System für verschachteltes Scrollen ermöglicht die Koordination zwischen scrollbaren und hierarchisch verknüpften Komponenten (meistens durch die gemeinsame Nutzung desselben übergeordneten Elements). Dieses System verknüpft Scrolling-Container und ermöglicht die Interaktion mit den Scrolling-Deltas, die weitergegeben und geteilt werden.
Compose bietet mehrere Möglichkeiten, um verschachteltes Scrollen zwischen Composables zu verarbeiten. Ein typisches Beispiel für das verschachtelte Scrollen ist eine Liste in einer anderen Liste. Ein komplexeres Beispiel ist eine minimierbare Symbolleiste.
Automatisches verschachteltes Scrollen
Für einfaches verschachteltes Scrollen ist kein Handlungsbedarf Ihrerseits erforderlich. Gesten, die eine Scrollaktion auslösen, werden automatisch von untergeordneten an übergeordnete Elemente weitergegeben. Wenn das untergeordnete Element also nicht weiter gescrollt werden kann, wird die Geste vom übergeordneten Element verarbeitet.
Automatisches verschachteltes Scrollen wird von einigen Compose-Komponenten und ‑Modifikatoren unterstützt und ist standardmäßig verfügbar, z. B. bei verticalScroll
, horizontalScroll
, scrollable
, Lazy
-APIs und TextField
. Wenn der Nutzer also ein untergeordnetes Element einer verschachtelten Komponente scrollt, werden die Scroll-Deltas durch die vorherigen Modifizierer an die übergeordneten Elemente weitergegeben, die verschachteltes Scrollen unterstützen.
Im folgenden Beispiel werden Elemente mit dem Modifikator verticalScroll
in einem Container dargestellt, auf den ebenfalls 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) ) } } } } }
nestedScroll
-Modifikator verwenden
Wenn Sie einen erweiterten koordinierten Scrollvorgang zwischen mehreren Elementen erstellen müssen, bietet der Modifier nestedScroll
mehr Flexibilität, da er eine verschachtelte Scrollhierarchie definiert. Wie im vorherigen Abschnitt erwähnt, unterstützen einige Komponenten das verschachtelte Scrollen. Bei Composables, die nicht automatisch gescrollt werden können, z. B. Box
oder Column
, werden die Scroll-Deltas für solche Komponenten jedoch nicht im verschachtelten Scrollsystem weitergegeben und erreichen weder NestedScrollConnection
noch die übergeordnete Komponente. Um dieses Problem zu beheben, können Sie nestedScroll
verwenden, um anderen Komponenten, einschließlich benutzerdefinierten Komponenten, diese Unterstützung zu gewähren.
Verschachtelter Scrollzyklus
Der verschachtelte Scrollzyklus ist der Fluss von Scroll-Deltas, die über alle Komponenten (oder Knoten) des verschachtelten Scrollsystems hinweg nach oben und unten im Hierarchiestrukturbaum verteilt werden, z. B. mithilfe von scrollbaren Komponenten und Modifizierern oder nestedScroll
.
Phasen des verschachtelten Scrollvorgangs
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 Scrollsytem gesendet und durchlaufen drei Phasen: Pre-Scroll, Node Consumption und Post-Scroll.
In der ersten Phase vor dem Scrollen werden die Triggerereignis-Deltas von der Komponente, die das Triggerereignis empfangen hat, über den Hierarchiebaum an das oberste übergeordnete Element gesendet. Die Delta-Ereignisse werden dann nach unten weitergegeben, d. h., Deltas werden vom übergeordneten Element der obersten Ebene bis zum untergeordneten Element weitergegeben, das den verschachtelten Scrollzyklus gestartet hat.
So können die verschachtelten Scroll-Parents (Composables mit nestedScroll
oder scrollbaren Modifikatoren) etwas mit dem Delta tun, bevor der Knoten selbst es verarbeiten kann.
In der Phase des Knotenverbrauchs verwendet der Knoten selbst das Delta, das nicht von seinen übergeordneten Elementen verwendet wurde. Hier wird die Scrollbewegung tatsächlich ausgeführt und ist sichtbar.
In dieser Phase kann das Kind den verbleibenden Scrollbereich ganz oder teilweise nutzen. Alles, was übrig bleibt, wird wieder nach oben gesendet, um die Phase nach dem Scrollen zu durchlaufen.
In der Phase nach dem Scrollen wird alles, was der Knoten selbst nicht verarbeitet hat, wieder an seine übergeordneten Elemente gesendet.
Die Post-Scroll-Phase funktioniert ähnlich wie die Pre-Scroll-Phase. Hier kann jedes der übergeordneten Elemente entscheiden, ob es das Signal verarbeitet oder nicht.
Ähnlich wie beim Scrollen kann die Intention des Nutzers nach Abschluss einer Ziehbewegung in eine Geschwindigkeit umgewandelt werden, mit der der scrollbare Container animiert wird. Der Fling ist auch Teil des verschachtelten Scrollzyklus und die durch das Drag-Ereignis generierten Geschwindigkeiten durchlaufen ähnliche Phasen: Pre-Fling, Node Consumption und Post-Fling. Die Fling-Animation ist nur mit der Touch-Geste verknüpft und wird nicht durch andere Ereignisse wie A11Y oder Hardware-Scrollen ausgelöst.
Am Zyklus für verschachteltes Scrollen teilnehmen
Die Teilnahme am Zyklus bedeutet, dass Sie die Nutzung von Deltas entlang der Hierarchie abfangen, nutzen und darüber berichten. Compose bietet eine Reihe von Tools, mit denen Sie beeinflussen können, wie das System für verschachteltes Scrollen funktioniert und wie Sie direkt damit interagieren können. Das ist beispielsweise nützlich, wenn Sie etwas mit den Scroll-Deltas tun müssen, bevor eine scrollbare Komponente überhaupt mit dem Scrollen beginnt.
Wenn der verschachtelte Scrollzyklus ein System ist, das auf eine Kette von Knoten wirkt, ist der Modifier nestedScroll
eine Möglichkeit, diese Änderungen abzufangen und einzufügen und die Daten (Scroll-Deltas) zu beeinflussen, die in der Kette weitergegeben werden. Dieser Modifikator kann an einer beliebigen Stelle in der Hierarchie platziert werden. Er kommuniziert mit verschachtelten Scrollmodifikator-Instanzen im Baum, um Informationen über diesen Kanal weiterzugeben. 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 Verbrauchsphasen darstellen: vor/nach dem Scrollen und vor/nach dem 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 zum weitergegebenen Delta: available
-Delta für die jeweilige Phase und consumed
-Delta, das in den vorherigen Phasen verwendet wurde. Wenn Sie die Weitergabe von Deltas in der Hierarchie beenden möchten, können Sie die verschachtelte Scrollverbindung 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 enthalten Informationen zum NestedScrollSource
-Typ.
Mit NestedScrollDispatcher
wird der verschachtelte Scrollzyklus initialisiert. Der Zyklus wird durch die Verwendung eines Dispatchers und den Aufruf seiner Methoden ausgelöst. Scrollbare Container haben einen integrierten Dispatcher, der Deltas, die während Gesten erfasst werden, an das System sendet. Aus diesem Grund wird in den meisten Anwendungsfällen zum Anpassen des verschachtelten Scrollens NestedScrollConnection
anstelle eines Dispatchers verwendet, um auf bereits vorhandene Deltas zu reagieren, anstatt neue zu senden.
Weitere Anwendungsbeispiele finden Sie unter NestedScrollDispatcherSample
.
Bildgröße beim Scrollen anpassen
Wenn der Nutzer scrollt, können Sie einen dynamischen visuellen Effekt erstellen, bei dem sich die Größe des Bildes je nach Scrollposition ändert.
Größe eines Bildes basierend auf der Scrollposition anpassen
In diesem Snippet wird gezeigt, wie ein Bild in einem LazyColumn
basierend auf der vertikalen Scrollposition skaliert wird. Das Bild wird kleiner, wenn der Nutzer nach unten scrollt, und größer, wenn er nach oben scrollt. Dabei bleibt es innerhalb der festgelegten Mindest- und Höchstgröße:
@Composable fun ImageResizeOnScrollExample( modifier: Modifier = Modifier, maxImageSize: Dp = 300.dp, minImageSize: Dp = 100.dp ) { var currentImageSize by remember { mutableStateOf(maxImageSize) } var imageScale by remember { mutableFloatStateOf(1f) } val nestedScrollConnection = remember { object : NestedScrollConnection { override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { // Calculate the change in image size based on scroll delta val delta = available.y val newImageSize = currentImageSize + delta.dp val previousImageSize = currentImageSize // Constrain the image size within the allowed bounds currentImageSize = newImageSize.coerceIn(minImageSize, maxImageSize) val consumed = currentImageSize - previousImageSize // Calculate the scale for the image imageScale = currentImageSize / maxImageSize // Return the consumed scroll amount return Offset(0f, consumed.value) } } } Box(Modifier.nestedScroll(nestedScrollConnection)) { LazyColumn( Modifier .fillMaxWidth() .padding(15.dp) .offset { IntOffset(0, currentImageSize.roundToPx()) } ) { // Placeholder list items items(100, key = { it }) { Text( text = "Item: $it", style = MaterialTheme.typography.bodyLarge ) } } Image( painter = ColorPainter(Color.Red), contentDescription = "Red color image", Modifier .size(maxImageSize) .align(Alignment.TopCenter) .graphicsLayer { scaleX = imageScale scaleY = imageScale // Center the image vertically as it scales translationY = -(maxImageSize.toPx() - currentImageSize.toPx()) / 2f } ) } }
Wichtige Punkte zum Code
- In diesem Code wird ein
NestedScrollConnection
verwendet, um Scroll-Ereignisse abzufangen. - Mit
onPreScroll
wird die Änderung der Bildgröße basierend auf dem Scroll-Delta berechnet. - Die Statusvariable
currentImageSize
speichert die aktuelle Größe des Bildes, die zwischenminImageSize
undmaxImageSize. imageScale
liegt und auscurrentImageSize
abgeleitet wird. - Die
LazyColumn
-Korrekturen basieren auf demcurrentImageSize
. - Für die
Image
wird der ModifikatorgraphicsLayer
verwendet, um die berechnete Skalierung anzuwenden. - Durch die
translationY
innerhalb dergraphicsLayer
bleibt das Bild beim Skalieren vertikal zentriert.
Ergebnis
Das oben stehende Snippet führt zu einem Skalierungseffekt beim Scrollen:
Interop für verschachteltes Scrollen
Wenn Sie versuchen, scrollbare View
-Elemente in scrollbaren Composables zu verschachteln oder umgekehrt, können Probleme auftreten. Am deutlichsten wird das, wenn Sie das untergeordnete Element scrollen und die Start- oder Endbegrenzung erreichen und erwarten, dass das übergeordnete Element das Scrollen übernimmt. Es kann jedoch sein, dass dieses erwartete Verhalten nicht eintritt oder nicht wie erwartet funktioniert.
Dieses Problem ist auf die Erwartungen zurückzuführen, die in scrollbaren Composables enthalten sind.
Für scrollbare Composables gilt die Regel „nested-scroll-by-default“. Das bedeutet, dass jeder scrollbare Container an der verschachtelten Scrollkette beteiligt sein muss, sowohl als übergeordnetes Element über NestedScrollConnection
als auch als untergeordnetes Element über NestedScrollDispatcher
.
Das untergeordnete Element würde dann einen verschachtelten Scrollvorgang für das übergeordnete Element auslösen, wenn es sich an der Grenze befindet. Mit dieser Regel können beispielsweise Compose Pager
und Compose LazyRow
gut zusammenarbeiten. Wenn jedoch mit ViewPager2
oder RecyclerView
gescrollt wird, ist das kontinuierliche Scrollen vom untergeordneten zum übergeordneten Element nicht möglich, da diese NestedScrollingParent3
nicht implementieren.
Wenn Sie die API für die Interoperabilität von verschachteltem Scrollen zwischen scrollbaren View
-Elementen und scrollbaren Composables aktivieren möchten, die in beide Richtungen verschachtelt sind, können Sie die API für die Interoperabilität von verschachteltem Scrollen in den folgenden Szenarien verwenden, um diese Probleme zu beheben.
Ein kooperierender Elternteil View
mit einem Kind ComposeView
Ein kooperierendes Eltern-Composable View
implementiert bereits NestedScrollingParent3
und kann daher Scrolling-Deltas von einem kooperierenden verschachtelten untergeordneten Composable empfangen. ComposeView
würde in diesem Fall als Kind agieren und NestedScrollingChild3
(indirekt) implementieren müssen.
Ein Beispiel für einen kooperierenden Elternteil ist androidx.coordinatorlayout.widget.CoordinatorLayout
.
Wenn Sie die Interoperabilität von verschachteltem Scrolling zwischen scrollbaren View
-Übergeordneten-Containern und verschachtelten scrollbaren untergeordneten Composables benötigen, können Sie rememberNestedScrollInteropConnection()
verwenden.
rememberNestedScrollInteropConnection()
ermöglicht und speichert die
NestedScrollConnection
, die die Interoperabilität von verschachtelten Scrollvorgängen zwischen einem View
-Übergeordneten, der
NestedScrollingParent3
und einem Compose-Untergeordneten implementiert, ermöglicht. Dieser Parameter sollte in Verbindung mit dem Modifikator nestedScroll
verwendet werden. Da das verschachtelte Scrollen auf der Compose-Seite standardmäßig aktiviert ist, können Sie diese Verbindung verwenden, um das verschachtelte Scrollen auf der View
-Seite zu aktivieren und die erforderliche Glue-Logik zwischen Views
und Composables hinzuzufügen.
Ein häufiger Anwendungsfall ist die Verwendung von CoordinatorLayout
, CollapsingToolbarLayout
und einer untergeordneten Composable-Funktion, wie in diesem Beispiel gezeigt:
<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>
In Ihrer Aktivität oder Ihrem Fragment müssen Sie das untergeordnete Composable und die erforderliche NestedScrollConnection
einrichten:
open class MainActivity : ComponentActivity() { 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()) } } } } } } }
Ein übergeordnetes Composable, das ein untergeordnetes AndroidView
enthält
In diesem Szenario geht es um die Implementierung der Nested Scrolling Interop API auf der Compose-Seite, wenn Sie eine übergeordnete Composable mit einem untergeordneten AndroidView
haben. Die AndroidView
implementiert NestedScrollDispatcher
, da sie als untergeordnetes Element eines Compose-Scrolling-übergeordneten Elements fungiert, sowie NestedScrollingParent3
, da sie als übergeordnetes Element eines View
-Scrolling-untergeordneten Elements fungiert. Der übergeordnete Compose-Container kann dann verschachtelte Scroll-Deltas von einem verschachtelten scrollbaren untergeordneten View
empfangen.
Das folgende Beispiel zeigt, wie Sie in diesem Szenario die Interoperabilität von verschachteltem Scrollen zusammen mit einer zusammenklappbaren Toolbar in Compose erreichen 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) {
// ...
}
}
// ...
}
In diesem Beispiel wird gezeigt, wie Sie die API mit dem Modifikator scrollable
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)
}
}
)
}
}
Dieses Beispiel zeigt, wie die API für die Interoperabilität von verschachteltem Scrollen mit BottomSheetDialogFragment
verwendet wird, um ein erfolgreiches Drag-and-Dismiss-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
}
}
}
Beachten Sie, dass mit
rememberNestedScrollInteropConnection()
ein
NestedScrollConnection
in das Element eingefügt wird, an das Sie es anhängen. NestedScrollConnection
ist für die Übertragung der Deltas von der Compose-Ebene auf die View
-Ebene verantwortlich. Dadurch kann das Element am verschachtelten Scrollen teilnehmen, aber das Scrollen von Elementen wird nicht automatisch aktiviert. Bei Composables, die nicht automatisch gescrollt werden, z. B. Box
oder Column
, werden Scroll-Deltas für solche Komponenten nicht im verschachtelten Scrollsystem weitergegeben und erreichen nicht die von rememberNestedScrollInteropConnection()
bereitgestellte NestedScrollConnection
. Daher erreichen diese Deltas nicht die übergeordnete View
-Komponente. Um dieses Problem zu beheben, müssen Sie auch für diese Arten von verschachtelten Composables scrollbare Modifikatoren festlegen. Weitere Informationen finden Sie im vorherigen Abschnitt zum verschachtelten Scrollen.
Ein nicht kooperierender Elternteil View
mit einem Kind ComposeView
Eine nicht kooperierende View implementiert die erforderlichen NestedScrolling
-Schnittstellen auf der View
-Seite nicht. Das bedeutet, dass die Interoperabilität von verschachteltem Scrollen mit diesen Views
nicht sofort funktioniert. Nicht kooperierende Views
sind RecyclerView
und ViewPager2
.
Zusätzliche Ressourcen
Empfehlungen für dich
- Hinweis: Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Gesten
CoordinatorLayout
zu Compose migrieren- Ansichten in Compose verwenden