Jetpack Compose Paging3+retrofit2封装(二)下拉刷新上拉加载

983 阅读3分钟

「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战

简单了解SwipeRefresh

是一种实现刷新模式的布局,允许用户通过垂直刷手势刷新内容。 他的布局要求其内容可滚动,以便接收垂直滑动事件。不过,可滚动内容不需要是直接的后代。布局,如androidx。组成地基懒惰的LazyColumn是自动可滚动的,但其他的如androidx。组成地基布局列要求您提供androidx。组成地基垂直滚动修改器到该内容。

应用程序应提供onRefresh块,以便在每次完成“刷到刷新”手势时收到通知。该块负责适当地更新状态,通常通过设置SwipeRefreshState。启动“刷新”后,IsRefresh将变为true。刷新完成后,应用程序应设置SwiperFreshState。我的看法是错误的。

如果应用程序希望在滑动手势之外显示进度动画,则可以设置滑动状态。i根据需要进行磨光。

此布局不会剪裁任何内容,包括指示器。如果需要剪辑,应用程序可以提供androidx。组成用户界面。画clipToBounds修饰符。

一般用stateonRefresh
state:用于控制或观察状态的状态对象。
onRefresh:在完成刷卡刷新手势时调用。
剩下的是一些配置了,有想法的深入了解

state对应着rememberSwipeRefreshState

rememberSwipeRefreshState:创建一个在合成中被记住的状态。
会对isRefreshing的更改而导致更新
参数:isRefreshing

封装流程

我们的目的是封装起来,所以要了解流程

定义状态

val rememberSwipeRefreshState = rememberSwipeRefreshState(isRefreshing = false)

SwipeRefresh


lazyPagingItems: LazyPagingItems<T>,
onRefresh: (() -> Unit) = {}
...
SwipeRefresh(
    state = rememberSwipeRefreshState,
    onRefresh = {
        onRefresh.invoke()
        lazyPagingItems.refresh()
    }
)

首先定义刷新状态

rememberSwipeRefreshState.isRefreshing =
    ((lazyPagingItems.loadState.refresh is LoadState.Loading) || isRefreshing)

把LazyColumn放在SwipeRefresh里面

itemContent: LazyListScope.() -> Unit
...
LazyColumn(
    modifier = Modifier.fillMaxSize(),
    horizontalAlignment = Alignment.CenterHorizontally,
    state = listState
) {
    //条目布局
    itemContent()
}

衍生加载中和 加载错误

           //加载更多状态:加载中和加载错误,没有更多
            when (loadState.append) {
                is LoadState.Loading -> 加载中
                is LoadState.Error -> 加载错误
                is LoadState.NotLoading -> {
                    if (loadState.append.endOfPaginationReached) {
                        //到低了
                    }
                }
            }

完整代码

@Composable
fun <T : Any> RefreshList(
    lazyPagingItems: LazyPagingItems<T>,
    isRefreshing: Boolean = false,
    onRefresh: (() -> Unit) = {},
    listState: LazyListState = rememberLazyListState(),
    itemContent: LazyListScope.() -> Unit,
) {
    val rememberSwipeRefreshState = rememberSwipeRefreshState(isRefreshing = false)
    //错误页
    val err = lazyPagingItems.loadState.refresh is LoadState.Error
    if (err) {
        ErrorContent { lazyPagingItems.retry() }
        return
    }

        SwipeRefresh(
        state = rememberSwipeRefreshState,
        onRefresh = {
            onRefresh.invoke()
            lazyPagingItems.refresh()
        }
    ) {
        //刷新状态
        rememberSwipeRefreshState.isRefreshing =
            ((lazyPagingItems.loadState.refresh is LoadState.Loading) || isRefreshing)
        //列表
        LazyColumn(
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            state = listState
        ) {
            //条目布局
            itemContent()
            //加载更多状态:加载中和加载错误,没有更多
            if (!rememberSwipeRefreshState.isRefreshing) {
                item {
                    lazyPagingItems.apply {
                        when (loadState.append) {
                            is LoadState.Loading -> LoadingItem()
                            is LoadState.Error -> ErrorItem { retry() }
                            is LoadState.NotLoading -> {
                                if (loadState.append.endOfPaginationReached) {
                                    NoMoreItem()
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

@Composable
fun ErrorContent(retry: () -> Unit) {
    Box(modifier = Modifier.fillMaxSize()) {
        Column(modifier = Modifier.align(Alignment.Center)) {
            Image(
                painter = painterResource(id = R.drawable.stat_notify_error),
                contentDescription = null,
                colorFilter = ColorFilter.tint(Color.Red),
                modifier = Modifier.align(Alignment.CenterHorizontally)
            )
            Text(
                text = "请求出错啦",
                modifier = Modifier
                    .align(Alignment.CenterHorizontally)
                    .padding(top = 10.dp)
            )
            Button(
                onClick = { retry() },
                modifier = Modifier
                    .align(Alignment.CenterHorizontally)
                    .padding(10.dp),
                colors = buttonColors(backgroundColor = AppTheme.colors.themeUi)
            ) {
                Text(text = "重试")
            }
        }
    }
}

@Composable
fun ErrorItem(retry: () -> Unit) {
    Button(
        onClick = { retry() },
        modifier = Modifier.padding(10.dp),
        colors = buttonColors(backgroundColor = AppTheme.colors.themeUi)
    ) {
        Text(text = "重试")
    }
}

@Composable
fun NoMoreItem() {
    Text(
        text = "没有更多了",
        modifier = Modifier
            .padding(10.dp)
            .fillMaxWidth(),
        textAlign = TextAlign.Center
    )
}

@Composable
fun LoadingItem() {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(60.dp), contentAlignment = Alignment.Center
    ) {
        CircularProgressIndicator(
            color = AppTheme.colors.themeUi,
            modifier = Modifier
                .padding(10.dp)
                .height(50.dp)
        )
    }
}

ViewModel

private val pager by lazy {
    simplePager {
       //it = 加载的页数 
       //根据页数来请求数据
        service.getSquareData(it)
    }.cachedIn(viewModelScope)
}

var viewStates by mutableStateOf(ViewState(pagingData = pager))
    private set
data class ViewState(
    val isRefreshing: Boolean = false,
    val listState: LazyListState = LazyListState(),
    val pagingData: Paging
)


typealias Paging = Flow<PagingData<数据实体>>

渲染UI

val viewStates = remember { viewModel.viewStates }

val squareData = viewStates.pagingData.collectAsLazyPagingItems()

val listState = if (squareData.itemCount > 0) viewStates.listState else LazyListState()

RefreshList(squareData, listState = listState) {
    itemsIndexed(squareData) { _, item ->
       //Item
    }
}