pref: 加载更多防抖

This commit is contained in:
HuanCheng65 2023-07-23 23:00:06 +08:00
parent 5248ce6cf8
commit 7925c36f07
No known key found for this signature in database
GPG Key ID: 5EC9DD60A32C7360
1 changed files with 54 additions and 9 deletions

View File

@ -2,15 +2,30 @@ package com.huanchengfly.tieba.post.ui.widgets.compose
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.* import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.FractionalThreshold
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -27,12 +42,17 @@ import androidx.compose.ui.unit.dp
import com.huanchengfly.tieba.post.R import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
import com.huanchengfly.tieba.post.ui.common.theme.compose.loadMoreIndicator import com.huanchengfly.tieba.post.ui.common.theme.compose.loadMoreIndicator
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.roundToInt import kotlin.math.roundToInt
private val LoadDistance = 70.dp private val LoadDistance = 70.dp
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class, FlowPreview::class)
@Composable @Composable
fun LoadMoreLayout( fun LoadMoreLayout(
isLoading: Boolean, isLoading: Boolean,
@ -50,17 +70,42 @@ fun LoadMoreLayout(
) { ) {
val loadDistance = with(LocalDensity.current) { LoadDistance.toPx() } val loadDistance = with(LocalDensity.current) { LoadDistance.toPx() }
val curOnLoadMore by rememberUpdatedState(newValue = onLoadMore)
var lastTriggerTime by remember { mutableStateOf(0L) }
var waitingStateReset by remember { mutableStateOf(false) }
val loadMoreFlow = remember {
MutableSharedFlow<Long>(
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_LATEST
)
}
val coroutineScope = rememberCoroutineScope()
DisposableEffect(Unit) {
val job = coroutineScope.launch {
loadMoreFlow
.sample(500)
.collect {
curOnLoadMore()
waitingStateReset = true
lastTriggerTime = it
}
}
onDispose { job.cancel() }
}
val canLoadMore = remember(enableLoadMore, loadEnd) { enableLoadMore && !loadEnd } val canLoadMore = remember(enableLoadMore, loadEnd) { enableLoadMore && !loadEnd }
val curIsLoading by rememberUpdatedState(newValue = isLoading) val curIsLoading by rememberUpdatedState(newValue = isLoading)
val curCanLoadMore by rememberUpdatedState(newValue = canLoadMore) val curCanLoadMore by rememberUpdatedState(newValue = canLoadMore)
var waitingStateReset by remember { mutableStateOf(false) }
val swipeableState = rememberSwipeableState(false) { newValue -> val swipeableState = rememberSwipeableState(false) { newValue ->
if (newValue && !curIsLoading && curCanLoadMore) { if (newValue && !curIsLoading && curCanLoadMore) {
onLoadMore() val curTime = System.currentTimeMillis()
waitingStateReset = true coroutineScope.launch {
true loadMoreFlow.emit(curTime)
}
curTime - lastTriggerTime >= 500
} else !newValue } else !newValue
} }
@ -71,6 +116,8 @@ fun LoadMoreLayout(
} }
} }
LaunchedEffect(isLoading) { swipeableState.animateTo(isLoading) }
Box( Box(
modifier = Modifier modifier = Modifier
.nestedScroll(swipeableState.LoadPreUpPostDownNestedScrollConnection) .nestedScroll(swipeableState.LoadPreUpPostDownNestedScrollConnection)
@ -96,8 +143,6 @@ fun LoadMoreLayout(
indicator(isLoading, loadEnd, swipeableState.targetValue) indicator(isLoading, loadEnd, swipeableState.targetValue)
} }
} }
LaunchedEffect(isLoading) { swipeableState.animateTo(isLoading) }
} }
} }