Scroll-Modifikatoren
Mit den Modifikatoren verticalScroll
und horizontalScroll
können Nutzer ganz einfach durch ein Element scrollen, wenn die Begrenzungen des Inhalts größer als die maximal zulässige Größe sind. Mit den Modifikatoren verticalScroll
und horizontalScroll
müssen Sie den Inhalt 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. Wenn Sie sie mit Standardparametern erstellen möchten, 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)) } } }
Modifizierer für scrollbare Inhalte
Der Modifikator scrollable
unterscheidet sich von den Scrollmodifikatoren dadurch, dass scrollable
die Scrollgesten erkennt und die Deltas erfasst, den Inhalt aber nicht automatisch verschiebt. Dies wird stattdessen über ScrollableState
an den Nutzer delegiert, was für die korrekte Funktion dieses Modifikators erforderlich ist.
Wenn Sie ScrollableState
erstellen, müssen Sie eine consumeScrollDelta
-Funktion angeben, die bei jedem Scrollschritt (durch Touch-Eingabe, gleitendes Scrollen oder Wischen) mit dem Delta in Pixeln aufgerufen wird. Diese Funktion muss die zurückgelegte Scrolldistanz zurückgeben, damit das Ereignis in Fällen mit verschachtelten Elementen mit dem Modifikator scrollable
ordnungsgemäß weitergegeben wird.
Im folgenden Snippet werden die Touch-Gesten erkannt und ein numerischer Wert für einen Versatz angezeigt, es werden jedoch keine Elemente verschoben:
@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()) } }
Verschachtelte Scrollbalken
Verschachteltes Scrollen ist ein System, bei dem mehrere ineinander enthaltene Scrollkomponenten zusammenarbeiten, indem sie auf eine einzelne Scrollgeste reagieren und ihre Scroll-Deltas (Änderungen) kommunizieren.
Das verschachtelte Scrollsystem ermöglicht die Koordination von Komponenten, die scrollbar und hierarchisch verknüpft sind (meistens durch gemeinsames übergeordnetes Element). Dieses System verknüpft scrollende Container und ermöglicht die Interaktion mit den Scroll-Deltas, die weitergegeben und geteilt werden.
Compose bietet mehrere Möglichkeiten, verschachtelte Scrollvorgänge zwischen Composables zu verarbeiten. Ein typisches Beispiel für verschachtelte Scrollbalken ist eine Liste in einer anderen Liste. Ein komplexerer Fall ist eine minimierbare Symbolleiste.
Automatisches verschachteltes Scrollen
Bei einfachem verschachtelten Scrollen sind keine Maßnahmen von Ihnen erforderlich. Touch-Gesten, die eine Scrollaktion initiieren, werden automatisch von untergeordneten Elementen an übergeordnete Elemente weitergegeben. Wenn das untergeordnete Element nicht mehr weiter scrollen kann, wird die Geste vom übergeordneten Element verarbeitet.
Das automatische verschachtelte Scrollen wird von einigen Komponenten und Modifikatoren von Compose unterstützt und ist standardmäßig verfügbar: verticalScroll
, horizontalScroll
, scrollable
, Lazy
APIs und TextField
. Das bedeutet, dass beim Scrollen durch ein inneres untergeordnetes Element verschachtelter Komponenten die vorherigen Modifikatoren die Scroll-Deltas an die übergeordneten Elemente weitergeben, die verschachtelte Scrollfunktionen unterstützen.
Das folgende Beispiel zeigt Elemente mit dem Modifikator verticalScroll
in einem Container, auf den ebenfalls der Modifikator verticalScroll
angewendet wurde.
@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 eine erweiterte, koordinierte Bildlauffunktion zwischen mehreren Elementen erstellen möchten, bietet Ihnen der Modifikator nestedScroll
mehr Flexibilität, da Sie eine verschachtelte Bildlaufhierarchie definieren können. Wie im vorherigen Abschnitt erwähnt, haben einige Komponenten eine integrierte Unterstützung für verschachtelte Scrollbalken. Bei Composables, die nicht automatisch scrollbar sind, z. B. Box
oder Column
, werden Scroll-Deltas für diese Komponenten nicht in das verschachtelte Scrollsystem übertragen und erreichen weder die NestedScrollConnection
noch die übergeordnete Komponente. Sie können dieses Problem beheben, indem Sie mit nestedScroll
anderen Komponenten, einschließlich benutzerdefinierten Komponenten, diese Unterstützung zuweisen.
Verschachtelter Scrollzyklus
Ein verschachtelter Scrollzyklus ist der Fluss von Scroll-Deltas, die durch den Hierarchiebaum hinauf und hinunter durch alle Komponenten (oder Knoten) gesendet werden, die Teil des verschachtelten Scrollsystems sind, z. B. durch Scrollkomponenten 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: Vor dem Scrollen, Knotenverbrauch und Nach dem Scrollen.
In der ersten Phase vor dem Scrollen sendet die Komponente, die die Triggerereignisdeltas empfangen hat, diese Ereignisse durch den Hierarchiebaum an das oberste übergeordnete Element. Die Deltaereignisse werden dann nach unten weitergegeben, d. h., Deltas werden vom übergeordneten Element ganz oben nach unten zum untergeordneten Element weitergegeben, das den verschachtelten Scrollzyklus gestartet hat.
So haben die verschachtelten übergeordneten Elemente für die Bildlaufsteuerung (mit nestedScroll
oder scrollbaren Modifikatoren) die Möglichkeit, etwas mit dem Delta zu tun, bevor der Knoten selbst es verwenden kann.
In der Phase der Knotennutzung verwendet der Knoten selbst das Delta, das von seinen übergeordneten Knoten nicht verwendet wurde. In diesem Fall wird die Scrollbewegung tatsächlich ausgeführt und ist sichtbar.
Während dieser Phase kann das Kind entscheiden, ob es den gesamten oder einen Teil des verbleibenden Scrollbereichs nutzen möchte. Alles, was übrig bleibt, wird zurückgesendet, um die Phase nach dem Scrollen zu durchlaufen.
In der Phase nach dem Scrollen werden alle Daten, die der Knoten selbst nicht verbraucht hat, noch einmal an seine Vorfahren gesendet.
Die Phase nach dem Scrollen funktioniert ähnlich wie die Phase vor dem Scrollen. Dabei kann jedes übergeordnete Element ausgewählt werden.
Ähnlich wie beim Scrollen kann die Absicht des Nutzers nach Abschluss einer Ziegesten in eine Geschwindigkeit umgewandelt werden, mit der der scrollbare Container „flingt“ (mit einer Animation scrollt). Der Wisch ist auch Teil des verschachtelten Scrollzyklus und die Geschwindigkeiten, die durch das Drag-Ereignis generiert werden, durchlaufen ähnliche Phasen: Vor dem Wischen, Knotenverbrauch und Nach dem Wischen. Die Wischanimation ist nur mit Touch-Gesten verknüpft und wird nicht durch andere Ereignisse wie a11y oder Hardware-Scrollen ausgelöst.
Am verschachtelten Scrollzyklus teilnehmen
Die Teilnahme am Zyklus bedeutet, dass Deltas entlang der Hierarchie abgefangen, verwendet und erfasst werden. Compose bietet eine Reihe von Tools, mit denen Sie die Funktionsweise des verschachtelten Scrollsystems beeinflussen und direkt damit interagieren können. Das ist beispielsweise dann nützlich, wenn Sie etwas mit den Scroll-Deltas tun müssen, bevor eine scrollbare Komponente überhaupt scrollt.
Wenn der verschachtelte Scrollzyklus ein System ist, das auf eine Kette von Knoten wirkt, können Sie mit dem Modifikator nestedScroll
diese Änderungen abfangen und einfügen und so die Daten (Scroll-Deltas) beeinflussen, die in der Kette weitergegeben werden. Dieser Modifikator kann überall in der Hierarchie platziert werden und kommuniziert mit verschachtelten Scroll-Modifikatorinstanzen im Baum, um Informationen über diesen Kanal zu teilen. Die Bausteine dieses Modifiers 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 Nutzungsphasen repräsentieren: Vor-/Nach-Scrollen und Vor-/Nach-Wischen:
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 Rückruf enthält auch Informationen zum übertragenen Delta: available
Delta für diese bestimmte Phase und consumed
Delta, das in den vorherigen Phasen verbraucht wurde. Wenn Sie die Weiterleitung von Deltas durch die Hierarchie nicht mehr zulassen 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.
NestedScrollDispatcher
initialisiert den verschachtelten Scrollzyklus. Durch die Verwendung eines Dispatchers und das Aufrufen seiner Methoden wird der Zyklus ausgelöst. Scrollbare Container haben einen integrierten Dispatcher, der während von Touch-Gesten erfasste Deltas an das System sendet. Aus diesem Grund wird bei den meisten Anwendungsfällen für die Anpassung verschachtelten Scrollens NestedScrollConnection
anstelle eines Dispatchers verwendet, um auf bereits vorhandene Deltas zu reagieren, anstatt neue zu senden.
Weitere Verwendungsmöglichkeiten finden Sie unter NestedScrollDispatcherSample
.
Bildgröße beim Scrollen anpassen
Wenn der Nutzer scrollt, können Sie einen dynamischen visuellen Effekt erstellen, bei dem sich das Bild je nach Scrollposition ändert.
Größe eines Bildes anhand der Scrollposition anpassen
In diesem Snippet wird gezeigt, wie die Größe eines Bildes in einem LazyColumn
basierend auf der vertikalen Scrollposition geändert wird. Das Bild schrumpft, wenn der Nutzer nach unten scrollt, und wird 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 Scrollereignisse abzufangen. onPreScroll
berechnet die Änderung der Bildgröße basierend auf dem Scroll-Delta.- Die Statusvariable
currentImageSize
speichert die aktuelle Größe des Bildes, die zwischenminImageSize
undmaxImageSize. imageScale
liegen muss und voncurrentImageSize
abgeleitet wird. - Die
LazyColumn
-Abweichungen basieren auf demcurrentImageSize
. - Für
Image
wird eingraphicsLayer
-Modifikator verwendet, um die berechnete Skala anzuwenden. - Durch das
translationY
ingraphicsLayer
bleibt das Bild beim Skalieren vertikal zentriert.
Ergebnis
Das vorherige Snippet führt beim Scrollen zu einem Bildskalierungseffekt:
Interoperabilität für verschachteltes Scrollen
Wenn Sie scrollbare View
-Elemente in scrollbare Composeables verschachteln oder umgekehrt, können Probleme auftreten. Am auffälligsten sind sie, wenn Sie das untergeordnete Element scrollen und dessen Anfang oder Ende erreichen und erwarten, dass das übergeordnete Element das Scrollen übernimmt. Dieses erwartete Verhalten tritt jedoch möglicherweise nicht auf oder funktioniert nicht wie erwartet.
Dieses Problem ist auf die Erwartungen zurückzuführen, die in scrollbaren Komponenten geweckt werden.
Für scrollbare Elemente gilt die Regel „nested-scroll-by-default“. Das bedeutet, dass jeder scrollbare Container an der verschachtelten Scrollreihenfolge teilnehmen muss, sowohl als übergeordnetes Element über NestedScrollConnection
als auch als untergeordnetes Element über NestedScrollDispatcher
.
Das untergeordnete Element würde dann ein verschachteltes Scrollen für das übergeordnete Element auslösen, wenn es sich an der Grenze befindet. Mit dieser Regel können beispielsweise „Komponieren Pager
“ und „Komponieren LazyRow
“ gut zusammenarbeiten. Wenn das Scrollen für die Interoperabilität jedoch mit ViewPager2
oder RecyclerView
erfolgt, ist ein kontinuierliches Scrollen von untergeordnet zu übergeordnet nicht möglich, da diese Tasten NestedScrollingParent3
nicht implementieren.
Wenn Sie die Nested Scrolling Interop API zwischen scrollbaren View
-Elementen und scrollbaren Composeables aktivieren möchten, die in beide Richtungen verschachtelt sind, können Sie diese Probleme in den folgenden Fällen mithilfe der Nested Scrolling Interop API beheben.
Ein übergeordnetes Element View
mit einem untergeordneten Element ComposeView
Ein kooperatives übergeordnetes Element View
ist ein Element, das bereits NestedScrollingParent3
implementiert hat und daher Scroll-Deltas von einem kooperativen verschachtelten untergeordneten Element empfangen kann. ComposeView
würde in diesem Fall als untergeordnetes Element fungieren und NestedScrollingChild3
(indirekt) implementieren müssen.
Ein Beispiel für ein kooperierendes Elternteil ist androidx.coordinatorlayout.widget.CoordinatorLayout
.
Wenn Sie die Interoperabilität zwischen scrollbaren View
-Übergeordneten-Containern und verschachtelten scrollbaren untergeordneten Composeables benötigen, können Sie rememberNestedScrollInteropConnection()
verwenden.
rememberNestedScrollInteropConnection()
ermöglicht und speichert den Wert NestedScrollConnection
, der die Interoperabilität zwischen einem übergeordneten View
-Element, das NestedScrollingParent3
implementiert, und einem untergeordneten Compose-Element ermöglicht. Dieser sollte in Verbindung mit einem Modifier vom Typ nestedScroll
verwendet werden. Da verschachteltes Scrollen auf der Compose-Seite standardmäßig aktiviert ist, können Sie mit dieser Verbindung sowohl das verschachtelte Scrollen auf der View
-Seite aktivieren als auch die erforderliche Logik zwischen Views
und Compose-Elementen hinzufügen.
Ein häufiger Anwendungsfall ist die Verwendung von CoordinatorLayout
, CollapsingToolbarLayout
und einem untergeordneten Composeable, 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 Composeable und die erforderlichen 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 Composeable mit einem untergeordneten AndroidView
In diesem Szenario wird die Implementierung der verschachtelten Scrolling Interop API auf der Compose-Seite behandelt, wenn ein übergeordnetes Compose-Element ein untergeordnetes AndroidView
enthält. Das Element AndroidView
implementiert NestedScrollDispatcher
, da es als untergeordnetes Element eines übergeordneten Elements mit scrollbarem Inhalt von Compose dient, sowie NestedScrollingParent3
, da es als übergeordnetes Element eines scrollbaren untergeordneten Elements von View
dient. Das übergeordnete Element kann dann verschachtelte Scroll-Deltas von einem verschachtelten scrollbaren untergeordneten Element View
empfangen.
Im folgenden Beispiel wird gezeigt, wie Sie in diesem Szenario die verschachtelte Bildlauf-Interoperabilität sowie eine minimierbare Symbolleiste für die Erstellung von Inhalten erreichen:
@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 du die API mit einem scrollable
-Modifikator verwendest:
@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 Nested Scrolling Interop API mit BottomSheetDialogFragment
verwendet wird, um ein erfolgreiches Ziehen und Schließen zu ermöglichen:
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
im Element installiert wird, an das Sie es anhängen. NestedScrollConnection
ist für die Übertragung der Deltas von der Compose-Ebene an die View
-Ebene verantwortlich. Dadurch kann das Element am verschachtelten Scrollen teilnehmen, aber es wird nicht automatisch gescrollt. Bei Composables, die nicht automatisch scrollbar sind, z. B. Box
oder Column
, werden Scroll-Deltas dieser Komponenten nicht im verschachtelten Scrollsystem weitergegeben und erreichen nicht die von rememberNestedScrollInteropConnection()
bereitgestellte NestedScrollConnection
. Daher erreichen diese Deltas auch nicht die übergeordnete View
-Komponente. Um dieses Problem zu beheben, müssen Sie für diese Arten von verschachtelten Composeable-Elementen auch scrollbare Modifikatoren festlegen. Weitere Informationen finden Sie im vorherigen Abschnitt zum verschachtelten Scrollen.
Ein nicht kooperatives übergeordnetes Element View
mit einem untergeordneten Element ComposeView
Eine nicht kooperative Ansicht ist eine Ansicht, die die erforderlichen NestedScrolling
-Schnittstellen auf der View
-Seite nicht implementiert. Das bedeutet, dass die Interoperabilität von verschachteltem Scrollen mit diesen Views
nicht standardmäßig funktioniert. Nicht kooperative Views
sind RecyclerView
und ViewPager2
.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Gesten
CoordinatorLayout
zu Compose migrieren- Ansichten in der compose-Ansicht verwenden