You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose LazyList中实现滚动到底部动态加载数据

Jetpack Compose 实现 LazyList 滚动到底部加载更多

在Jetpack Compose中,可以通过LazyListState结合状态推导实现类似RecyclerView的滚动到底部加载更多功能,核心是监听列表滚动位置,判断到达末尾后触发数据加载。以下是完整实现方案:

1. 数据状态管理(ViewModel)

推荐用ViewModel封装数据加载逻辑,避免界面重建时重复请求:

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class ItemViewModel : ViewModel() {
    private val _allItems = MutableStateFlow<List<String>>(emptyList())
    val allItems: StateFlow<List<String>> = _allItems

    private val _isLoading = MutableStateFlow(false)
    val isLoading: StateFlow<Boolean> = _isLoading

    private val _hasNextPage = MutableStateFlow(true)
    val hasNextPage: StateFlow<Boolean> = _hasNextPage

    private var currentPage = 1

    init {
        // 初始化加载第一页数据
        loadNextPage()
    }

    fun loadNextPage() {
        // 防止重复请求或无更多数据时触发
        if (_isLoading.value || !_hasNextPage.value) return

        _isLoading.value = true
        viewModelScope.launch {
            // 替换为你的实际API请求逻辑,根据返回的next_page判断是否还有下一页
            delay(1000)
            val newItems = List(20) { "Item ${_allItems.value.size + it + 1}" }
            _allItems.value += newItems
            currentPage++

            // 模拟无更多数据的场景,实际根据API返回的next_page更新_hasNextPage
            if (currentPage > 3) {
                _hasNextPage.value = false
            }
            _isLoading.value = false
        }
    }
}

2. LazyList 滚动监听与加载逻辑

在Compose界面中,利用LazyListState检测滚动位置,结合LaunchedEffect触发加载:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun InfiniteScrollList() {
    val viewModel: ItemViewModel = viewModel()
    val allItems = viewModel.allItems.collectAsState()
    val isLoading = viewModel.isLoading.collectAsState()
    val hasNextPage = viewModel.hasNextPage.collectAsState()
    val lazyListState = rememberLazyListState()

    // 推导是否需要加载更多的状态
    val shouldLoadMore = remember {
        derivedStateOf {
            val lastVisibleIndex = lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
            // 判断最后一个可见项是否接近列表末尾,同时满足加载条件
            lastVisibleIndex != null && 
            lastVisibleIndex >= allItems.value.size - 1 && 
            hasNextPage.value && 
            !isLoading.value
        }
    }

    // 当shouldLoadMore为true时触发加载
    LaunchedEffect(shouldLoadMore.value) {
        if (shouldLoadMore.value) {
            viewModel.loadNextPage()
        }
    }

    Box(modifier = Modifier.fillMaxSize()) {
        LazyColumn(
            state = lazyListState,
            modifier = Modifier.fillMaxSize()
        ) {
            items(allItems.value) { item ->
                Text(
                    text = item,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(16.dp)
                )
            }

            // 底部加载指示器
            if (isLoading.value) {
                item {
                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(16.dp),
                        contentAlignment = Alignment.Center
                    ) {
                        CircularProgressIndicator()
                    }
                }
            }
        }
    }
}

关键逻辑说明

  • LazyListState:通过rememberLazyListState()获取列表的滚动状态和可见项信息,替代RecyclerView的OnScrollListener。
  • derivedStateOf:用于计算是否需要加载更多的状态,仅当依赖的lazyListState、allItems等状态变化时才重新计算,避免无效触发。
  • LaunchedEffect:监听shouldLoadMore的变化,符合条件时调用ViewModel的加载方法,确保在Compose的协程环境中执行异步操作。
  • 状态防护:通过isLoading防止重复请求,hasNextPage避免无数据时继续触发API调用,提升体验。

内容的提问来源于stack exchange,提问作者Stɑrry Shivɑm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 13:35:15