Listen und Raster

In vielen Apps müssen Sammlungen von Elementen angezeigt werden. In diesem Dokument wird erläutert, wie Sie ist das mit Jetpack Compose effizient möglich.

Wenn Sie wissen, dass für Ihren Anwendungsfall kein Scrollen erforderlich ist, Verwenden Sie ein einfaches Column oder Row (je nach Richtung) und geben Sie den Inhalt jedes Elements aus, indem Sie wie folgt ü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, Die Verwendung eines Layouts wie Column kann zu Leistungsproblemen führen, da alle Elemente zusammengesetzt sind und unabhängig davon, ob sie sichtbar sind oder nicht, dargestellt werden.

„Compose“ bietet eine Reihe von Komponenten, die nur Elemente im Darstellungsbereich der Komponente sichtbar sind. Zu diesen Komponenten 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. LazyColumn eine Liste, die vertikal scrollt, und LazyRow eine horizontal in einer scrollbaren Liste.

Die Lazy-Komponenten unterscheiden sich von den meisten Layouts in Compose. Anstelle von Sie können den Parameter @Composable für die Inhaltsblockierung akzeptieren, sodass Apps direkt zusammensetzbare Funktionen ausgeben, stellen die Lazy-Komponenten einen LazyListScope.()-Block bereit. 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

Der DSL von LazyListScope bietet eine Reihe von Funktionen zur Beschreibung 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 Sammlung von Elementen, z. B. 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 die gleichen leistungsstarken API-Funktionen wie Listen. Sie verwenden außerdem DSL sehr ähnlich. LazyGridScope.() zur Beschreibung des Inhalts.

Screenshot eines Smartphones mit einem Raster von Fotos

Der columns-Parameter in LazyVerticalGrid und rows in LazyHorizontalGrid wie Zellen in Spalten oder Zeilen umgewandelt werden. Die folgenden werden Elemente in einem Raster dargestellt, GridCells.Adaptive So legen Sie fest, dass jede Spalte mindestens 128.dp breit ist:

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 wird dann Spalten wie möglich einfügen. Die verbleibende Breite wird gleichmäßig verteilt nach der Berechnung der Spaltenanzahl. 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 in Ihrem Design nur bestimmte Elemente nicht standardmäßige Abmessungen haben müssen, können Sie mithilfe der Rasterunterstützung benutzerdefinierte Spalten-Spans für Elemente angeben. Geben Sie den Spaltenbereich mit dem Parameter span der LazyGridScope DSL item- und items-Methoden. maxLineSpan, einer der Werte für den Span-Bereich, ist besonders nützlich, wenn Sie adaptive Größenanpassung, 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")
    }
    // ...
}

Verzögertes, gestaffeltes Raster

LazyVerticalStaggeredGrid und LazyHorizontalStaggeredGrid sind zusammensetzbare Funktionen, mit denen Sie ein Lazy-Loading-Raster von Elementen erstellen können. Ein vertikal gestaffeltes Raster zeigt seine Elemente so an, dass sie vertikal scrollbar sind. Container, der sich über mehrere Spalten erstreckt und mit dem einzelne Elemente mit unterschiedlichen Höhen. 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()
)

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
Abbildung 1. Beispiel für ein verzögertes vertikales vertikales Raster

Um eine feste Anzahl von Spalten festzulegen, können Sie StaggeredGridCells.Fixed(columns) statt StaggeredGridCells.Adaptive. Die verfügbare Breite wird durch die Anzahl der Spalten (oder Zeilen für eine horizontales Raster) und jedes Element nimmt diese Breite (bzw. Höhe horizontales Raster):

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()
)

<ph type="x-smartling-placeholder">
</ph> Verzögertes, gestaffeltes Bildraster in Compose
Abbildung 2. Beispiel für ein verzögertes vertikales vertikales Raster mit festen Spalten

Abstände im Inhalt

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 16.dp an den horizontalen Rändern (links und rechts) und dann auf 8.dp am oberen und unteren Rand des Inhalts.

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

Um den Abstand zwischen den Elementen zu erhöhen, können Sie Arrangement.spacedBy() Im folgenden Beispiel wird zwischen den einzelnen Elementen ein Leerzeichen (4.dp) eingefü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 von der Position des Elements im Liste oder Raster. Dies kann jedoch zu Problemen führen, wenn sich der Datensatz ändert, da Elemente, die dass die Positionsänderung faktisch alle gespeicherten Informationen verliert. Wenn Sie sich vorstellen, LazyRow-Szenario innerhalb einer LazyColumn, wenn die Zeile die Elementposition ändert verliert der Nutzer seine Scrollposition innerhalb der Zeile.

Um dies zu verhindern, können Sie für jedes Element einen stabilen und eindeutigen Schlüssel bereitstellen, einen Block zum Parameter key hinzu. Wenn Sie einen stabilen Schlüssel bereitstellen, kann der Artikelstatus 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 Artikel beispielsweise den Status „merkt“ enthält, würden Einstellungsschlüssel erlauben, Schreiben Sie, um diesen Status zusammen mit dem Element zu verschieben, 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 Typ des Schlüssels muss von Bundle, der Android-Mechanismus, mit dem wird angezeigt, wenn die Aktivität neu erstellt wird. Bundle unterstützt Typen wie Primitive, enums 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()
        }
    }
}

Elementanimationen

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. Sie müssen nur animateItemPlacement Modifizierer für den Artikelinhalt verwenden:

LazyColumn {
    items(books, key = { it.id }) {
        Row(Modifier.animateItemPlacement()) {
            // ...
        }
    }
}

Sie können sogar eine Spezifikation für benutzerdefinierte Animationen angeben, wenn Folgendes erforderlich ist:

LazyColumn {
    items(books, key = { it.id }) {
        Row(
            Modifier.animateItemPlacement(
                tween(durationMillis = 250)
            )
        ) {
            // ...
        }
    }
}

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

Abgesehen von Neuanordnungen werden derzeit Animationen zum Hinzufügen und Entfernen von Elementen in der Entwicklungsphase ist. Du kannst den Fortschritt hier verfolgen: 150812265.

Fixierte Überschriften (experimentell)

Das Muster „fixierte Kopfzeile“ ist bei der Anzeige von Listen gruppierter Daten hilfreich. Unten sehen Sie ein Beispiel für eine Kontaktliste, die nach den Anfang:

Video eines Smartphones, das durch eine Kontaktliste nach oben und unten scrollt

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 Scrollposition reagieren

Viele Apps müssen auf Änderungen an der Scrollposition und dem Layout von Elementen reagieren und darauf achten. Die Lazy-Komponenten unterstützen diesen Anwendungsfall, indem sie die LazyListState:

@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 meist nur Informationen über die erste sichtbares Element. In diesem Fall LazyListState stellt die firstVisibleItemIndex und firstVisibleItemScrollOffset Eigenschaften.

Wenn wir das Beispiel des Anzeigen- und Ausblendens einer Schaltfläche verwenden, je nachdem, ob die Nutzenden über das erste Element hinaus gescrollt haben:

@OptIn(ExperimentalAnimationApi::class)
@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()
        }
    }
}

Es ist nützlich, den Status direkt in der Zusammensetzung zu lesen, wenn Sie eine Aktualisierung vornehmen müssen anderen zusammensetzbaren Funktionen der Benutzeroberfläche. Es gibt aber auch Szenarien, in denen das Ereignis in derselben Komposition behandelt werden. Ein gängiges Beispiel dafür ist das Senden einer wenn der Nutzer an einem bestimmten Punkt weiterscrollt. 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 in der LazyListLayoutInfo .

Scrollposition steuern

Es ist nicht nur nützlich, wenn Apps auf die Scrollposition reagieren, auch die Scroll-Position. LazyListState unterstützt dies über scrollToItem() , die das Objekt "sofort" einrastet. Scrollposition und animateScrollToItem() bei dem mit einer Animation gescrollt wird (auch als flüssiges Scrollen bezeichnet):

@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 Datensätze (Pging)

Mit der Paging Library können Apps lange Listen von Elementen unterstützen, kleine Listenelemente als notwendig ist. Paging 3.0 und höher bietet Compose-Unterstützung über die androidx.paging:paging-compose-Bibliothek.

Um eine Liste von Seiteninhalten anzuzeigen, können wir die Methode collectAsLazyPagingItems() Erweiterungsfunktion und übergeben die zurückgegebene LazyPagingItems an items() in unserem LazyColumn. Ähnlich wie die Paging-Unterstützung in Ansichten können Sie Platzhalter während des Ladens der Daten anzeigen, indem Sie prüfen, ob item auf null gesetzt 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, die Sie berücksichtigen können, damit 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 beispielsweise erwarten, um bestimmte Daten wie Bilder abzurufen, um die Listeneinträge zu füllen. Dies würde dazu führen, dass das Lazy-Layout alle Elemente im ersten da ihre Höhe 0 Pixel beträgt und sie alle in das Darstellungsbereich. 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 innerhalb eines anderen scrollbaren übergeordneten Elements aus derselben Richtung. 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, wenn Sie alle zusammensetzbaren Funktionen zusammenfassen. in einem übergeordneten LazyColumn und verwendet dessen DSL, um verschiedene Arten von Inhalte. So können sowohl einzelne als auch mehrere Listenelemente ausgegeben werden. alles an einem Ort:

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

Denken Sie daran, dass Fälle, in denen Sie verschiedene Richtungslayouts verschachteln, Beispielsweise sind ein scrollbarer übergeordneter Row und ein untergeordneter LazyColumn zulässig:

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 Lambda-Element 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 ausgegeben werden, werden sie wie d. h., sie können nicht mehr einzeln zusammengestellt werden. 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. Im Extremfall, dass alle Elemente in ein Element den Zweck der Verwendung von Lazy-Layouts vollständig zunichte. 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 möchten nicht, dass Trennlinien das Scrollen ändern. da sie nicht als unabhängige 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

Normalerweise enthalten Lazy Listen viele Elemente, die mehr als die Größe der scrollbarer Container. Wenn Ihre Liste jedoch nur wenige Einträge enthält, Design kann spezifischere Anforderungen an die Positionierung dieser Elemente haben. im Darstellungsbereich befinden.

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

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

Beginnen Sie mit Compose 1.2, um die Leistung Ihrer Lazy- hinzufügen, fügen Sie contentType Listen oder Rastern hinzufügen. Damit können Sie den Inhaltstyp für jede des Layouts erstellen, wenn Sie eine Liste oder ein Raster aus von verschiedenen Arten von Elementen:

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

Wenn Sie die contentType, Mit „Compose“ können nur Kompositionen wiederverwendet werden zwischen den Elementen desselben Typs. Da die Wiederverwendung effizienter ist, Elemente ähnlicher Struktur zusammensetzen. Durch die Bereitstellung der Inhaltstypen Beim Schreiben wird nicht versucht, ein Element des Typs A über einem ein anderes Element des Typs B. So können Sie die Vorteile der Zusammenstellung und die Leistung des Lazy-Layouts.

Leistungsmessung

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