简介
在使用compose制作UI时发现,compose只提供了水平方向的进度条,但是项目中需要使用垂直方向的进度条,于是动手自己组合了一个,支持拖拽;直接上代码
@Composable
fun VerticalSlider(
modifier: Modifier,
progress: Int,
maxProgress: Int = 100,
onValueChange: (Int) -> Unit) {
BoxWithConstraints(modifier = modifier) {
val thumbSize = maxWidth
val length = maxHeight
val maxLengthPx = with(LocalDensity.current) {
(length - thumbSize).toPx()
}
var offsetX by remember(progress) {
mutableStateOf(maxLengthPx * (progress * 1f / maxProgress))
}
// 创建并获取一个DraggableState实例
val draggableState = rememberDraggableState {
// 使用回调方法回传的参数对状态偏移量进行累加,并限制范围
val newValue = (offsetX - it).coerceIn(0f, maxLengthPx)
if (newValue == offsetX) return@rememberDraggableState
offsetX = newValue
onValueChange.invoke((maxProgress * (abs(offsetX) / maxLengthPx)).roundToInt())
}
Spacer(
modifier = Modifier
.then(Modifier.pointerInput(this) {
detectTapGestures(
onTap = {
offsetX = (maxLengthPx - it.y)
onValueChange.invoke((maxProgress * (abs(offsetX) / maxLengthPx)).roundToInt())
}
)
})
.fillMaxHeight()
.width(thumbSize / 2)
.align(Alignment.BottomCenter)
.background(Color(0xFFDDE1ED), shape = RoundedCornerShape(50)))
Spacer(
modifier = Modifier
.height(with(LocalDensity.current) { offsetX.toDp() } + thumbSize / 2)
.width(thumbSize / 2)
.align(Alignment.BottomCenter)
.background(Color(0xff6297FF), shape = RoundedCornerShape(50)))
Card(
modifier = Modifier
.size(thumbSize)
.align(Alignment.BottomCenter)
.offset { IntOffset(0, -offsetX.roundToInt()) }
.draggable(
orientation = Orientation.Vertical,
state = draggableState
),
colors = CardDefaults.cardColors(containerColor = Color.White),
shape = CircleShape,
elevation = CardDefaults.elevatedCardElevation(defaultElevation = 1.dp)) {
Icon(
painter = painterResource(id = R.drawable.v_ic_volume),
tint = Color.Unspecified,
contentDescription = null,
modifier = Modifier
.padding(2.dp)
.fillMaxSize())
}
}
}
@Preview(showBackground = true)
@Composable
fun VerticalSliderPre() {
VerticalSlider(
modifier = Modifier
.width(10.dp)
.height(150.dp),
0) {}
}
效果