您可以使用rememberSaveable 存储所选项目索引,然后您可以使用AnimatedVisibility 为打开的视图设置动画。要添加我创建的 Modifier.swipeableTopBottom 的滑动,请在 this answer 中查看有关其工作原理的更多详细信息。
var selectedItem by rememberSaveable { mutableStateOf(0) }
val itemsCount = 10
Column(
verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier
.padding(10.dp)
.swipeableTopBottom(
onTop = {
selectedItem = (selectedItem - 1).coerceIn(0, itemsCount)
},
onBottom = {
selectedItem = (selectedItem + 1).coerceIn(0, itemsCount)
},
)
) {
repeat(itemsCount) { i ->
Column(
Modifier
.clickable {
selectedItem = i
}
.fillMaxWidth()
.background(Color.DarkGray)
.padding(10.dp)
) {
Text("Title $i")
AnimatedVisibility(visible = i == selectedItem) {
Column {
repeat(5) { j ->
Text("Subtitle $i $j")
}
}
}
}
}
}
Modifier.swipeableTopBottom:
fun Modifier.swipeableTopBottom(onTop: () -> Unit, onBottom: () -> Unit): Modifier = composed {
var width by rememberSaveable { mutableStateOf(0f) }
val swipeableState = rememberSwipeableState(
SwipeDirection.Initial,
animationSpec = snap()
)
val anchorWidth = remember(width) {
if (width == 0f) {
1f
} else {
width
}
}
val scope = rememberCoroutineScope()
if (swipeableState.isAnimationRunning) {
DisposableEffect(Unit) {
onDispose {
when (swipeableState.currentValue) {
SwipeDirection.Top -> {
onTop()
}
SwipeDirection.Bottom -> {
onBottom()
}
else -> {
return@onDispose
}
}
scope.launch {
swipeableState.snapTo(SwipeDirection.Initial)
}
}
}
}
return@composed Modifier
.onSizeChanged { width = it.width.toFloat() }
.swipeable(
state = swipeableState,
anchors = mapOf(
0f to SwipeDirection.Top,
anchorWidth / 2 to SwipeDirection.Initial,
anchorWidth to SwipeDirection.Bottom,
),
thresholds = { _, _ -> FractionalThreshold(0.3f) },
orientation = Orientation.Vertical
)
}
private enum class SwipeDirection(val raw: Int) {
Top(0),
Initial(1),
Bottom(2),
}
结果: