refactor: searchBar and list

This commit is contained in:
AnranYus
2024-06-15 23:03:46 +08:00
parent 1d208099f9
commit 329da172e8
2 changed files with 101 additions and 28 deletions
@@ -9,7 +9,10 @@ import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -37,17 +40,16 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
@@ -58,6 +60,8 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.lsp.view.bean.Post
@@ -78,7 +82,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.random.Random
private const val TAG = "Compose_PostActivity"
@@ -160,9 +164,46 @@ fun PostListScreen(
val postList by viewModel.postData.collectAsState()
val listState = rememberLazyStaggeredGridState()
val uiState by viewModel.uiState.collectAsState()
var lastScrollOffset by remember {
mutableIntStateOf(0)
}
var lastScrollPosition by remember {
mutableIntStateOf(0)
}
/**
* 1 scroll up
* -1 scroll down
* 0 default
*/
var scrollDirectionState by remember {
mutableIntStateOf(0)
}
val scope = rememberCoroutineScope()
var searchBarHeightSize by remember {
mutableStateOf(0.dp)
}
val density = LocalDensity.current
val searchBarPadding by remember {
mutableStateOf(24.dp)
}
LaunchedEffect(listState) {
snapshotFlow { listState.layoutInfo }.map { layoutInfo ->
snapshotFlow { listState.layoutInfo }.also{
it.collect{
if (lastScrollOffset<listState.firstVisibleItemScrollOffset && lastScrollPosition < listState.firstVisibleItemIndex){
scrollDirectionState = -1
}
if (lastScrollOffset > listState.firstVisibleItemScrollOffset && lastScrollPosition > listState.firstVisibleItemIndex){
scrollDirectionState = 1
}
lastScrollOffset = listState.firstVisibleItemScrollOffset
lastScrollPosition = listState.firstVisibleItemIndex
}
}.map { layoutInfo ->
layoutInfo.visibleItemsInfo.lastOrNull()?.index == postList.lastIndex
}.distinctUntilChanged().collect { reachedEnd ->
//避免初次加载数据时,list未绘制导致被判断为到达底部
@@ -172,24 +213,21 @@ fun PostListScreen(
}
}
val scope = rememberCoroutineScope()
Scaffold(topBar = {
Row(modifier = Modifier.padding(vertical = 12.dp)) {
SearchBar(uiState.searchTarget.value) {
viewModel.fetchPost(it, refresh = true)
scope.launch {
listState.animateScrollToItem(index = 0)
}
}
}
}, containerColor = Color.Transparent) {
Row {
Box(modifier = Modifier.fillMaxSize()) {
Column{
LazyVerticalStaggeredGrid(
state = listState,
columns = StaggeredGridCells.Adaptive(200.dp),
verticalItemSpacing = 4.dp,
horizontalArrangement = Arrangement.spacedBy(4.dp),
content = {
//放置两个item将下面的内容顶下来
items(count = 2, key = {
Random.nextInt()
}) {
Box(modifier = Modifier.height(searchBarHeightSize + searchBarPadding).fillMaxWidth())
}
items(items = postList, key = {
it.postId//提供key以保持列表顺序稳定
}) {
@@ -203,10 +241,47 @@ fun PostListScreen(
},
modifier = Modifier
.background(Color.Transparent)
.padding(top = it.calculateTopPadding())
)
}
AnimatedVisibility(
visible = scrollDirectionState != -1,
enter = slideInVertically(
// 进入动画,从顶部滑下
initialOffsetY = { -it },
animationSpec = tween(durationMillis = 300)
),
exit = slideOutVertically(
// 退出动画,向上滑动消失
targetOffsetY = { -it },
animationSpec = tween(durationMillis = 300)
)
) {
SearchBar(
modifier = Modifier
.padding(horizontal = 24.dp, vertical = searchBarPadding / 2)
.fillMaxWidth()
.wrapContentHeight()
.onGloballyPositioned {
searchBarHeightSize = with(density) {
it.size.height.toDp()
}
},
searchTarget = uiState.searchTarget.value
) {
viewModel.fetchPost(it, refresh = true)
scope.launch {
listState.animateScrollToItem(index = 0)
}
}
}
}
}
@Composable
@@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
@@ -22,7 +23,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.text.TextStyle
@@ -32,12 +32,9 @@ import androidx.compose.ui.unit.sp
@Composable
fun SearchBar(searchTarget: String = "", searchEvent: (String) -> Unit) {
fun SearchBar(modifier: Modifier = Modifier,searchTarget: String = "", searchEvent: (String) -> Unit) {
Row(
modifier = Modifier
.padding(horizontal = 24.dp)
.fillMaxWidth()
.height(56.dp)
modifier = modifier
.background(MaterialTheme.colorScheme.onPrimary, shape = RoundedCornerShape(56.dp)),
verticalAlignment = Alignment.CenterVertically
) {
@@ -46,8 +43,8 @@ fun SearchBar(searchTarget: String = "", searchEvent: (String) -> Unit) {
contentDescription = null,
modifier = Modifier
.padding(15.dp)
.height(48.dp)
.width(48.dp)
.height(30.dp)
.width(30.dp)
)
var input: String by remember { mutableStateOf(searchTarget) }
@@ -68,6 +65,7 @@ fun SearchBar(searchTarget: String = "", searchEvent: (String) -> Unit) {
},
modifier = Modifier
.weight(1f)
.wrapContentHeight()
.fillMaxWidth(),
)
@@ -76,8 +74,8 @@ fun SearchBar(searchTarget: String = "", searchEvent: (String) -> Unit) {
contentDescription = null,
modifier = Modifier
.padding(15.dp)
.height(48.dp)
.width(48.dp)
.height(30.dp)
.width(30.dp)
)
}