Listen und Raster

In vielen Apps müssen Sammlungen von Elementen angezeigt werden. In diesem Dokument wird beschrieben, wie Sie dies in Jetpack Compose effizient tun können.

Wenn Sie wissen, dass für Ihren Anwendungsfall kein Scrollen erforderlich ist, können Sie ein einfaches Column oder Row (je nach Richtung) verwenden und die Inhalte der einzelnen Elemente ausgeben, indem Sie auf folgende Weise über eine Liste iterieren:

@Composable
fun MessageList(messages: List<Message>) {
    Column {
        messages.forEach { message ->
            MessageRow(message)
        }
    }
}

Mit dem verticalScroll()-Modifikator können wir Column scrollbar machen.

Lazy-Listen

Wenn Sie eine große Anzahl von Elementen (oder eine Liste mit unbekannter Länge) anzeigen möchten, kann die Verwendung eines Layouts wie Column zu Leistungsproblemen führen, da alle Elemente zusammengesetzt und angeordnet werden, unabhängig davon, ob sie sichtbar sind oder nicht.

„Compose“ bietet eine Reihe von Komponenten, die nur Elemente bilden und im Darstellungsbereich der Komponente sichtbar sind. Dazu gehören LazyColumn und LazyRow.

Wie der Name schon sagt, ist der Unterschied zwischen LazyColumn und LazyRow ist die Ausrichtung, in der sie ihre Objekte anordnen und scrollen. Mit LazyColumn wird eine vertikal scrollbare Liste und mit LazyRow eine horizontal scrollbare Liste erzeugt.

Die Lazy-Komponenten unterscheiden sich von den meisten Layouts in Compose. Anstatt einen @Composable-Inhaltsblockparameter zu akzeptieren, mit dem Apps direkt Composables ausgeben können, bieten die Lazy-Komponenten einen LazyListScope.()-Block. Dieses LazyListScope Block bietet eine DSL, mit der Apps den Inhalt des Artikels beschreiben können. Die Die Lazy-Komponente ist dann dafür verantwortlich, die Inhalte der einzelnen Elemente die für das Layout und die Scroll-Position erforderlich sind.

LazyListScope DSL

Die DSL von LazyListScope bietet eine Reihe von Funktionen zum Beschreiben von Elementen im Layout. Ganz einfach: item() ein einzelnes Element hinzufügt und items(Int) fügt mehrere Elemente hinzu:

LazyColumn {
    // Add a single item
    item {
        Text(text = "First item")
    }

    // Add 5 items
    items(5) { index ->
        Text(text = "Item: $index")
    }

    // Add another single item
    item {
        Text(text = "Last item")
    }
}

Es gibt auch eine Reihe von Erweiterungsfunktionen, mit denen Sie Sammlungen von Elementen hinzufügen können, z. B. eine List. Mit diesen Erweiterungen können wir migrieren Sie unser Column-Beispiel von oben:

/**
 * import androidx.compose.foundation.lazy.items
 */
LazyColumn {
    items(messages) { message ->
        MessageRow(message)
    }
}

Es gibt auch eine Variante des items() Erweiterungsfunktion aufgerufen itemsIndexed(), das den Index bereitstellt. In der LazyListScope finden Sie weitere Informationen.

Lazy Grids

Die LazyVerticalGrid und LazyHorizontalGrid zusammensetzbare Funktionen bieten Unterstützung für die Anzeige von Elementen in einem Raster. Verzögertes vertikales Raster werden die Elemente in einem vertikal scrollbaren Container angezeigt, der sich über Spalten haben, während Lazy horizontal Grids dasselbe Verhalten auf der horizontalen Achse.

Raster haben dieselben leistungsstarken API-Funktionen wie Listen und verwenden auch eine sehr ähnliche DSL (LazyGridScope.()), um den Inhalt zu beschreiben.

Screenshot eines Smartphones mit einem Raster von Fotos

Mit dem Parameter columns in LazyVerticalGrid und dem Parameter rows in LazyHorizontalGrid wird festgelegt, wie Zellen in Spalten oder Zeilen angeordnet werden. Im folgenden Beispiel werden Elemente in einem Raster angezeigt. Mit GridCells.Adaptive wird festgelegt, dass jede Spalte mindestens 128.dp breit sein muss:

LazyVerticalGrid(
    columns = GridCells.Adaptive(minSize = 128.dp)
) {
    items(photos) { photo ->
        PhotoItem(photo)
    }
}

Mit LazyVerticalGrid können Sie eine Breite für Elemente angeben. Das Raster passt dann so gut wie möglich auf die Anzahl der Spalten. Die verbleibende Breite wird gleichmäßig auf die Spalten verteilt, nachdem die Anzahl der Spalten berechnet wurde. Diese adaptive Art der Größenanpassung ist besonders nützlich für die Darstellung von Gruppen von Elementen. für unterschiedliche Bildschirmgrößen.

Wenn Sie die genaue Anzahl der zu verwendenden Spalten kennen, können Sie stattdessen eine Instanz von GridCells.Fixed mit der Anzahl der erforderlichen Spalten.

Wenn für Ihr Design nur bestimmte Elemente nicht standardmäßige Abmessungen haben müssen, können Sie die Rasterunterstützung verwenden, um benutzerdefinierte Spaltenabstände für Elemente festzulegen. Geben Sie den Spaltenbereich mit dem Parameter span der LazyGridScope DSL item- und items-Methoden. maxLineSpan, einer der Werte für den Bereichsumfang, ist besonders nützlich, wenn Sie die adaptive Größe verwenden, da die Anzahl der Spalten nicht festgelegt ist. In diesem Beispiel wird gezeigt, wie Sie einen vollständigen Zeilenbereich angeben:

LazyVerticalGrid(
    columns = GridCells.Adaptive(minSize = 30.dp)
) {
    item(span = {
        // LazyGridItemSpanScope:
        // maxLineSpan
        GridItemSpan(maxLineSpan)
    }) {
        CategoryCard("Fruits")
    }
    // ...
}

Lazy staggered grid

LazyVerticalStaggeredGrid und LazyHorizontalStaggeredGrid sind Elemente, mit denen Sie ein Lazy-Load-Staggered-Grid mit Elementen erstellen können. In einem Lazy Vertical Staggered Grid werden die Elemente in einem vertikal scrollbaren Container angezeigt, der sich über mehrere Spalten erstreckt und es ermöglicht, dass einzelne Elemente unterschiedliche Höhen haben. Verzögerte horizontale Raster haben dasselbe Verhalten horizontale Achse mit Elementen unterschiedlicher Breite.

Das folgende Snippet ist ein einfaches Beispiel für die Verwendung von LazyVerticalStaggeredGrid mit einer Breite von 200.dp pro Element:

LazyVerticalStaggeredGrid(
    columns = StaggeredGridCells.Adaptive(200.dp),
    verticalItemSpacing = 4.dp,
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    content = {
        items(randomSizedPhotos) { photo ->
            AsyncImage(
                model = photo,
                contentScale = ContentScale.Crop,
                contentDescription = null,
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight()
            )
        }
    },
    modifier = Modifier.fillMaxSize()
)

Abbildung 1. Beispiel für ein verzögertes vertikales vertikales Raster

Wenn Sie eine feste Anzahl von Spalten festlegen möchten, können Sie anstelle von StaggeredGridCells.Adaptive die Zahl StaggeredGridCells.Fixed(columns) verwenden. Dabei wird die verfügbare Breite durch die Anzahl der Spalten (oder Zeilen bei einem horizontalen Raster) geteilt und jedes Element nimmt diese Breite (oder Höhe bei einem horizontalen Raster) ein:

LazyVerticalStaggeredGrid(
    columns = StaggeredGridCells.Fixed(3),
    verticalItemSpacing = 4.dp,
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    content = {
        items(randomSizedPhotos) { photo ->
            AsyncImage(
                model = photo,
                contentScale = ContentScale.Crop,
                contentDescription = null,
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight()
            )
        }
    },
    modifier = Modifier.fillMaxSize()
)
Verzögertes, gestaffeltes Bildraster in Compose
Abbildung 2. Beispiel für ein Lazy-Staggered-Vertikal-Raster mit festen Spalten

Textabstand

Manchmal müssen Sie an den Rändern des Inhalts einen Innenrand hinzufügen. Faulpelz Komponenten können einige PaddingValues contentPadding hinzu, um dies zu unterstützen:

LazyColumn(
    contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
) {
    // ...
}

In diesem Beispiel fügen wir den horizontalen Rändern (links und rechts) einen Abstand von 16.dp und dann oben und unten am Inhalt einen Abstand von 8.dp hinzu.

Dieser Abstand wird auf den content angewendet, nicht auf den LazyColumn selbst. Im Beispiel oben wird durch das erste Element 8.dp hinzugefügt. Abstand zum oberen Rand hinzugefügt, wird beim letzten Element 8.dp unten hinzugefügt und alle Elemente hat links und rechts einen Abstand von 16.dp.

Abstand zwischen Inhalten

Mit Arrangement.spacedBy() können Sie Abstände zwischen Elementen hinzufügen. Im folgenden Beispiel wird zwischen den einzelnen Elementen ein Abstand von 4.dp hinzugefügt:

LazyColumn(
    verticalArrangement = Arrangement.spacedBy(4.dp),
) {
    // ...
}

Gleiches gilt für LazyRow:

LazyRow(
    horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
    // ...
}

Raster können jedoch sowohl vertikal als auch horizontal angeordnet werden:

LazyVerticalGrid(
    columns = GridCells.Fixed(2),
    verticalArrangement = Arrangement.spacedBy(16.dp),
    horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
    items(photos) { item ->
        PhotoItem(item)
    }
}

Artikelschlüssel

Standardmäßig wird der Status jedes Elements anhand der Position des Elements in der Liste oder im Raster festgelegt. Dies kann jedoch zu Problemen führen, wenn sich der Datensatz ändert, da Elemente, die ihre Position ändern, ihren gespeicherten Status verlieren. Wenn Sie sich das Szenario von LazyRow in einer LazyColumn vorstellen, würde der Nutzer seine Scrollposition innerhalb der Zeile verlieren, wenn sich die Artikelposition in der Zeile ändert.

Um dies zu vermeiden, können Sie für jedes Element einen stabilen und eindeutigen Schlüssel angeben, der dem key-Parameter einen Block zuweist. Wenn Sie einen stabilen Schlüssel bereitstellen, kann der Elementstatus bei allen Dataset-Änderungen einheitlich sind:

LazyColumn {
    items(
        items = messages,
        key = { message ->
            // Return a stable + unique key for the item
            message.id
        }
    ) { message ->
        MessageRow(message)
    }
}

Durch die Angabe von Schlüsseln hilfst du Compose bei der korrekten Verarbeitung von Neuanordnungen. Wenn Ihr Element beispielsweise einen gespeicherten Status enthält, können Sie mithilfe von Schlüsseln festlegen, dass Compose diesen Status zusammen mit dem Element verschiebt, wenn sich seine Position ändert.

LazyColumn {
    items(books, key = { it.id }) {
        val rememberedValue = remember {
            Random.nextInt()
        }
    }
}

Es gibt jedoch eine Einschränkung hinsichtlich der Typen, die Sie als Elementschlüssel verwenden können. Der Schlüsseltyp muss von Bundle unterstützt werden, dem Android-Mechanismus zum Beibehalten der Status, wenn die Aktivität neu erstellt wird. Bundle unterstützt Typen wie primitive Typen, Enumerationen oder Parcelables.

LazyColumn {
    items(books, key = {
        // primitives, enums, Parcelable, etc.
    }) {
        // ...
    }
}

Der Schlüssel muss von Bundle unterstützt werden, sodass die rememberSaveable darin kann das zusammensetzbare Element wiederhergestellt werden, wenn die Activity-Klasse neu erstellt wird. wenn Sie von diesem Element weg und zurückscrollen.

LazyColumn {
    items(books, key = { it.id }) {
        val rememberedValue = rememberSaveable {
            Random.nextInt()
        }
    }
}

Artikelanimationen

Wenn Sie das RecyclerView-Widget verwendet haben, wissen Sie, dass es Element automatisch anpassen. Lazy Layouts bieten die gleiche Funktionalität für die Neuanordnung von Elementen. Die API ist einfach: Du musst nur den Modifikator animateItemPlacement für den Artikelinhalt festlegen:

LazyColumn {
    // It is important to provide a key to each item to ensure animateItem() works as expected.
    items(books, key = { it.id }) {
        Row(Modifier.animateItem()) {
            // ...
        }
    }
}

Sie können sogar eine benutzerdefinierte Animationsspezifikation angeben, wenn Folgendes erforderlich ist:

LazyColumn {
    items(books, key = { it.id }) {
        Row(
            Modifier.animateItem(
                fadeInSpec = tween(durationMillis = 250),
                fadeOutSpec = tween(durationMillis = 100),
                placementSpec = spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy)
            )
        ) {
            // ...
        }
    }
}

Stellen Sie sicher, dass Sie Schlüssel für Ihre Elemente angeben, damit Sie neue Position des verschobenen Elements an.

Fixierte Überschriften (experimentell)

Das Muster „fixierte Kopfzeile“ ist hilfreich, wenn Listen gruppierter Daten angezeigt werden. Unten sehen Sie ein Beispiel für eine Kontaktliste, die nach dem Anfangsbuchstaben der einzelnen Kontakte gruppiert ist:

Video eines Smartphones, auf dem eine Kontaktliste nach oben und unten gescrollt wird

Um mit LazyColumn eine fixierte Kopfzeile zu erstellen, können Sie die experimentelle stickyHeader() und geben den Header-Inhalt an:

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ListWithHeader(items: List<Item>) {
    LazyColumn {
        stickyHeader {
            Header()
        }

        items(items) { item ->
            ItemRow(item)
        }
    }
}

Um eine Liste mit mehreren Überschriften zu erstellen, wie im Beispiel mit der Kontaktliste oben, könnten Sie Folgendes tun:

// This ideally would be done in the ViewModel
val grouped = contacts.groupBy { it.firstName[0] }

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ContactsList(grouped: Map<Char, List<Contact>>) {
    LazyColumn {
        grouped.forEach { (initial, contactsForInitial) ->
            stickyHeader {
                CharacterHeader(initial)
            }

            items(contactsForInitial) { contact ->
                ContactListItem(contact)
            }
        }
    }
}

Auf die Scrollposition reagieren

Viele Apps müssen auf Änderungen der Scrollposition und des Artikellayouts reagieren und diese im Blick behalten. Die Lazy-Komponenten unterstützen diesen Anwendungsfall, indem sie die LazyListState hochskalieren:

@Composable
fun MessageList(messages: List<Message>) {
    // Remember our own LazyListState
    val listState = rememberLazyListState()

    // Provide it to LazyColumn
    LazyColumn(state = listState) {
        // ...
    }
}

Bei einfachen Anwendungsfällen benötigen Apps in der Regel nur Informationen zum ersten sichtbaren Element. In diesem Fall LazyListState stellt die firstVisibleItemIndex und firstVisibleItemScrollOffset Eigenschaften.

Angenommen, Sie möchten eine Schaltfläche je nachdem anzeigen oder ausblenden, ob der Nutzer den ersten Artikel übersprungen hat:

@Composable
fun MessageList(messages: List<Message>) {
    Box {
        val listState = rememberLazyListState()

        LazyColumn(state = listState) {
            // ...
        }

        // Show the button if the first visible item is past
        // the first item. We use a remembered derived state to
        // minimize unnecessary compositions
        val showButton by remember {
            derivedStateOf {
                listState.firstVisibleItemIndex > 0
            }
        }

        AnimatedVisibility(visible = showButton) {
            ScrollToTopButton()
        }
    }
}

Das Lesen des Status direkt in der Komposition ist nützlich, wenn Sie andere UI-Kompositionen aktualisieren müssen. Es gibt aber auch Szenarien, in denen das Ereignis nicht in derselben Komposition verarbeitet werden muss. Ein gängiges Beispiel hierfür ist das Senden eines Analytics-Ereignisses, wenn der Nutzer einen bestimmten Punkt im Scrollen erreicht hat. Um das Problem zu beheben können wir eine snapshotFlow():

val listState = rememberLazyListState()

LazyColumn(state = listState) {
    // ...
}

LaunchedEffect(listState) {
    snapshotFlow { listState.firstVisibleItemIndex }
        .map { index -> index > 0 }
        .distinctUntilChanged()
        .filter { it }
        .collect {
            MyAnalyticsService.sendScrolledPastFirstItemEvent()
        }
}

LazyListState bietet auch Informationen zu allen Artikeln, die derzeit und ihre Grenzen auf dem Bildschirm mithilfe der layoutInfo Property. Weitere Informationen finden Sie im Artikel zur Klasse LazyListLayoutInfo.

Scrollposition steuern

Neben der Reaktion auf die Scrollposition ist es auch nützlich, wenn Apps die Scrollposition steuern können. LazyListState unterstützt dies über die Funktion scrollToItem(), mit der die Scrollposition „sofort“ fixiert wird, und animateScrollToItem(), mit der per Animation (auch als „weiches Scrollen“ bezeichnet) gescrollt wird:

@Composable
fun MessageList(messages: List<Message>) {
    val listState = rememberLazyListState()
    // Remember a CoroutineScope to be able to launch
    val coroutineScope = rememberCoroutineScope()

    LazyColumn(state = listState) {
        // ...
    }

    ScrollToTopButton(
        onClick = {
            coroutineScope.launch {
                // Animate scroll to the first item
                listState.animateScrollToItem(index = 0)
            }
        }
    )
}

Große Datenmengen (Auslagerung)

Mit der Paginierungsbibliothek können Apps große Listen von Elementen unterstützen und bei Bedarf kleine Teile der Liste laden und anzeigen. Paging 3.0 und höher bietet Compose-Unterstützung über die androidx.paging:paging-compose-Bibliothek.

Um eine Liste mit paginierten Inhalten anzuzeigen, können wir die Erweiterungsfunktion collectAsLazyPagingItems() verwenden und dann die zurückgegebene LazyPagingItems an items() in unserer LazyColumn übergeben. Ähnlich wie bei der Unterstützung der Paginierung in Ansichten können Sie Platzhalter anzeigen, während Daten geladen werden. Dazu prüfen Sie, ob item null ist:

@Composable
fun MessageList(pager: Pager<Int, Message>) {
    val lazyPagingItems = pager.flow.collectAsLazyPagingItems()

    LazyColumn {
        items(
            lazyPagingItems.itemCount,
            key = lazyPagingItems.itemKey { it.id }
        ) { index ->
            val message = lazyPagingItems[index]
            if (message != null) {
                MessageRow(message)
            } else {
                MessagePlaceholder()
            }
        }
    }
}

Tipps zur Verwendung von Lazy-Layouts

Es gibt einige Tipps, mit denen Sie dafür sorgen können, dass Ihre Lazy-Layouts wie vorgesehen funktionieren.

Verwenden Sie keine Elemente mit einer Größe von 0 Pixeln.

Dies kann in Szenarien passieren, in denen Sie zum Beispiel erwarten, bestimmte Daten wie Bilder abzurufen, um die Listeneinträge zu füllen. Dadurch würden alle Elemente des Lazy-Layouts beim ersten Messwert erstellt, da ihre Höhe 0 Pixel beträgt und sie alle in den Darstellungsbereich passen würden. Sobald die Elemente geladen und ihre Höhe maximiert wurden, werden Lazy-Layouts werden dann alle anderen unnötigerweise erstellten Elemente verworfen. da sie nicht in den Darstellungsbereich passen. Um dies zu vermeiden, sollten Sie eine Standard-Größenanpassung für Ihre Elemente festlegen, damit das Lazy-Layout wie viele Elemente tatsächlich in den Darstellungsbereich passen:

@Composable
fun Item(imageUrl: String) {
    AsyncImage(
        model = rememberAsyncImagePainter(model = imageUrl),
        modifier = Modifier.size(30.dp),
        contentDescription = null
        // ...
    )
}

Wenn Sie die ungefähre Größe Ihrer Artikel kennen, nachdem die Daten asynchron geladen werden, sollten Sie darauf achten, dass die Größe Ihrer Artikel vor und nach dem Laden durch Hinzufügen von Platzhaltern identisch. Dies trägt dazu bei, die korrekte Scrollposition beizubehalten.

Verschachteln Sie keine Komponenten, die in dieselbe Richtung gescrollt werden können.

Dies gilt nur für Fälle, in denen scrollbare untergeordnete Elemente ohne vordefinierte Größe in einem anderen scrollbaren übergeordneten Element in derselben Richtung verschachtelt werden. Wenn Sie z. B. versuchen, ein untergeordnetes LazyColumn ohne feste Höhe in einem vertikal scrollbaren Column übergeordnetes Element:

// throws IllegalStateException
Column(
    modifier = Modifier.verticalScroll(state)
) {
    LazyColumn {
        // ...
    }
}

Stattdessen können Sie dasselbe Ergebnis erzielen, indem Sie alle Ihre Composeables in einem übergeordneten LazyColumn-Element einschließen und über dessen DSL unterschiedliche Inhaltstypen übergeben. So können einzelne Artikel sowie mehrere Listenelemente an einem Ort gesendet werden:

LazyColumn {
    item {
        Header()
    }
    items(data) { item ->
        PhotoItem(item)
    }
    item {
        Footer()
    }
}

Beachten Sie, dass das Verschachteln von Layouts mit unterschiedlicher Ausrichtung zulässig ist, z. B. ein scrollbares übergeordnetes Element Row und ein untergeordnetes Element LazyColumn:

Row(
    modifier = Modifier.horizontalScroll(scrollState)
) {
    LazyColumn {
        // ...
    }
}

Außerdem gibt es Fälle, in denen Sie immer noch dieselben Richtungslayouts verwenden, aber auch eine feste Größe für die verschachtelten untergeordneten Elemente:

Column(
    modifier = Modifier.verticalScroll(scrollState)
) {
    LazyColumn(
        modifier = Modifier.height(200.dp)
    ) {
        // ...
    }
}

Vorsicht, mehrere Elemente in einem Element zu platzieren

In diesem Beispiel gibt das zweite Element-Lambda zwei Elemente in einem Block aus:

LazyVerticalGrid(
    columns = GridCells.Adaptive(100.dp)
) {
    item { Item(0) }
    item {
        Item(1)
        Item(2)
    }
    item { Item(3) }
    // ...
}

Lazy Layouts behandeln dies wie erwartet – sie legen die ersten Elemente so als wären es unterschiedliche Elemente. Es gibt jedoch ein paar Probleme dabei.

Wenn mehrere Elemente als Teil eines Elements gesendet werden, werden sie als eine Entität behandelt. Das bedeutet, dass sie nicht mehr einzeln zusammengesetzt werden können. Wenn eine -Element auf dem Bildschirm sichtbar wird, dann erscheinen alle Elemente, die dem komponiert und gemessen werden müssen. Dies kann sich negativ auf die Leistung auswirken, wenn übermäßig oft verwendet wird. Wenn Sie im Extremfall alle Elemente in einem Element platzieren, entfällt der Zweck von Lazy-Layouts vollständig. Abgesehen von möglichen kann die Leistung beeinträchtigt werden, mit scrollToItem() und animateScrollToItem().

Es gibt jedoch sinnvolle Anwendungsfälle, um mehrere Elemente in ein Element wie Trennlinien in einer Liste. Sie sollten nicht möchten, dass Trennlinien die Scrollindexe ändern, da sie nicht als eigenständige Elemente betrachtet werden sollten. Außerdem ist die Leistung wird nicht beeinflusst, da die Trennlinien klein sind. Eine Trennlinie muss wahrscheinlich sichtbar, wenn das Element davor sichtbar ist, sodass es Teil des vorherigen Artikel:

LazyVerticalGrid(
    columns = GridCells.Adaptive(100.dp)
) {
    item { Item(0) }
    item {
        Item(1)
        Divider()
    }
    item { Item(2) }
    // ...
}

Individuelle Anordnungen in Betracht ziehen

In der Regel haben Lazy-Listen viele Elemente und nehmen mehr Platz ein als der scrollbare Container. Wenn Ihre Liste jedoch nur wenige Elemente enthält, kann Ihr Design spezifischere Anforderungen an die Positionierung dieser Elemente im Darstellungsbereich haben.

Dazu können Sie eine benutzerdefinierte Branche Arrangement verwenden und an die LazyColumn übergeben. Im folgenden Beispiel wird der TopWithFooter muss nur die Methode arrange implementiert werden. Erstens: Elemente nacheinander anzeigen. Zweitens: Wenn die insgesamt verwendete Höhe niedriger als die Höhe des Darstellungsbereichs ist, wird die Fußzeile unten platziert:

object TopWithFooter : Arrangement.Vertical {
    override fun Density.arrange(
        totalSize: Int,
        sizes: IntArray,
        outPositions: IntArray
    ) {
        var y = 0
        sizes.forEachIndexed { index, size ->
            outPositions[index] = y
            y += size
        }
        if (y < totalSize) {
            val lastIndex = outPositions.lastIndex
            outPositions[lastIndex] = totalSize - sizes.last()
        }
    }
}

Du kannst „contentType“ hinzufügen

Ab Compose 1.2 können Sie die Leistung Ihres Lazy-Layouts maximieren, indem Sie Ihren Listen oder Rastern contentType hinzufügen. So können Sie den Inhaltstyp für jedes Element des Layouts angeben, wenn Sie eine Liste oder ein Raster mit mehreren verschiedenen Elementtypen erstellen:

LazyColumn {
    items(elements, contentType = { it.type }) {
        // ...
    }
}

Wenn Sie contentType angeben, kann Compose Kompositionen nur zwischen Elementen desselben Typs wiederverwenden. Da die Wiederverwendung effizienter ist, wenn Sie Elemente mit ähnlicher Struktur erstellen, wird durch die Angabe der Inhaltstypen verhindert, dass „Compose“ versucht, ein Element vom Typ A auf einem völlig anderen Element vom Typ B zu erstellen. So lassen sich die Vorteile der Wiederverwendung von Kompositionen und die Leistung des Lazy-Layouts maximieren.

Leistung messen

Sie können die Leistung eines Lazy-Layouts nur zuverlässig messen, wenn Sie Release-Modus und mit aktivierter R8-Optimierung. Bei Debug-Builds kann das Scrollen mit dem Lazy Layout langsamer erscheinen. Weitere Informationen finden Sie unter Leistung von Kompositionen.