背景
最近遇到个需求,jetpack compose中要给列表的item加一个左滑删除菜单,左滑展示一个删除按钮,点击删除item,很简单的需求,然而Google了一圈,只发现了compose自带的SwipeToDismiss
和类似的一个开源库me.saket.swipe:swipe
比较有用,但是细看不太符合需求,SwipeToDismiss顾名思义就是滑动到某个地方item就会dismiss,不符合要求的swipe后点击再dismiss的需求啊(测试不接受你有啥办法),自己动手呗!!
swipe这个库写得比较简单且支持compose multiplatform,果断在这个库的基础上来修改。
先上成果
少啰嗦,先看东西!觉得有用的话给个star呗~
swipe-like-ios
swipe-like-ios
builds composables that can be swiped left or right for revealing actions
groovy
// settings.gradle.kts
repositories {
maven { setUrl("https://www.jitpack.io") }
}
// build.gradle.kts
implementation("com.linversion.swipe:swipe-like-ios:latest-version")
kotlin
val archive = SwipeAction(
icon = rememberVectorPainter(Icons.TwoTone.Archive),
background = Color.Green,
onClick = { ... }
)
val replyAll = SwipeAction(
icon = rememberVectorPainter(Icons.TwoTone.ReplyAll),
background = Color.Perfume,
onClick = { println("Reply swiped") }
)
val snooze = SwipeAction(
icon = { Text("Snooze") },
background = Color.Yellow,
onClick = { ... },
)
SwipeableActionsBox(
startActions = listOf(replyAll),
endActions = listOf(snooze, archive),
swipeThreshold = 80.dp,
) {
// Swipeable content goes here.
}
简单介绍一下实现原理
其实很简单,就是在item的左右两边分别用一个Row放置你的菜单(action),给个初始的offsetX,使得菜单刚好不可见,滑动的时候改变ofssetX,每个action平分滑动的空间,直到菜单完全展示后加一个阻尼的效果,完全仿照iOS的实现。
对比之下SwipeToDismiss的原理是在item的底部放一个Row来摆放你的action,滑动的时候就可以看到了。
滑动的监听则都是用Modifier的draggable
修饰符,然后给item设置absoluteOffset
kotlin
Box(
modifier = Modifier
.absoluteOffset { IntOffset(x = offsetX, y = 0) }
.draggable(
orientation = Horizontal,
enabled = !state.isResettingOnRelease,
onDragStopped = {
scope.launch {
state.handleOnDragStopped()
}
},
state = state.draggableState,
),
content = content
)
后续期望
仔细看了一下,iOS在有些场景也有SwipeToDismiss的效果,并且加了震动效果,后续会考虑拓展加上这个效果。