Skip to content

Instantly share code, notes, and snippets.

@programmerAbc
Last active February 6, 2023 10:11
Show Gist options
  • Select an option

  • Save programmerAbc/d768aaaf449cb301e01c6b9d2e765bda to your computer and use it in GitHub Desktop.

Select an option

Save programmerAbc/d768aaaf449cb301e01c6b9d2e765bda to your computer and use it in GitHub Desktop.
ABSlider
@Composable
fun ABSlider() {
Box(modifier = Modifier.fillMaxSize().padding(50.dp)) {
BoxWithConstraints(
modifier = Modifier.fillMaxWidth().height(50.dp)
.background(color = Color(0xaa000000))
.align(Alignment.Center)
) {
var useAB by remember { mutableStateOf(true) }
var positionA by remember { mutableStateOf(0f) }
var positionB by remember { mutableStateOf(1f) }
var position by remember { mutableStateOf(0.5f) }
var gap by remember { mutableStateOf(0.02f) }
val a = ImageBitmap.imageResource(R.drawable.ic_a)
val b = ImageBitmap.imageResource(R.drawable.ic_b)
val thumb = ImageBitmap.imageResource(R.drawable.ic_thumb)
val canvasWidth = with(LocalDensity.current) { maxWidth.toPx() }
val canvasHeight = with(LocalDensity.current) { maxHeight.toPx() }
val centerVertical = canvasHeight / 2f
val range = canvasWidth * 0.8f
val padStart = (canvasWidth - range) / 2f
val padEnd = padStart
val aSize = IntSize(48, 44)
val bSize = IntSize(48, 44)
val thumbSize = IntSize(60, 60)
var dragTarget = ""
Log.e("TAG", "ABSlider: canvas width $canvasWidth height $canvasHeight")
Canvas(
modifier = Modifier.fillMaxSize()
.pointerInput("tap") {
detectTapGestures { offset ->
val offsetPercent =
(offset.x - padStart).let {
if (it > 0) {
if (it < range)
it
else
range
} else 0f
} / range
if (useAB) {
if (offsetPercent <= positionA) {
positionA = offsetPercent
} else if (offsetPercent >= positionB) {
positionB = offsetPercent
} else {
position = offsetPercent
}
} else {
position = offsetPercent
}
}
}.pointerInput("drag") {
detectDragGestures(
onDragStart = { offset ->
val offsetPercent =
(offset.x - padStart).let {
if (it > 0) {
if (it < range)
it
else
1f
} else 0f
} / range
if (useAB) {
if (offsetPercent <= (positionA + 0.05f).let { if (it >= 1f) 1f else it }) {
dragTarget = "a"
positionA = offsetPercent
} else if (offsetPercent >= (positionB - 0.05f).let { if (it <= 0) 0f else it }) {
dragTarget = "b"
positionB = offsetPercent
} else {
dragTarget = "thumb"
position = offsetPercent
}
} else {
dragTarget = "thumb"
position = offsetPercent
}
Log.e("TAG", "ABSlider: drag target $dragTarget")
},
onDragCancel = {
dragTarget = ""
},
onDragEnd = {
dragTarget = ""
}) { change, dragAmount ->
Log.e("TAG", "ABSlider: dragAmount" + dragAmount)
when (dragTarget) {
"a" -> {
val delta = dragAmount.x.absoluteValue / range
positionA = if (dragAmount.x > 0) {
(positionA + delta + gap).let {
if (it >= positionB) {
(positionB - gap).let { result -> if (result > 0) result else 0f }
} else {
positionA + delta
}
}
} else {
(positionA - delta).let { if (it > 0) it else 0f }
}
if (position < positionA) {
position = positionA
}
}
"b" -> {
val delta = dragAmount.x.absoluteValue / range
positionB = if (dragAmount.x > 0) {
(positionB + delta).let {
if (it >= 1f) 1f else it
}
} else {
(positionB - delta - gap).let {
if (it <= positionA) {
(positionA + gap).let { result -> if (result >= 1f) 1f else result }
} else {
positionB - delta
}
}
}
if (position > positionB) {
position = positionB
}
}
"thumb" -> {
val delta = dragAmount.x.absoluteValue / range
position = if (dragAmount.x > 0) {
(position + delta).let {
if (useAB) {
if (it >= positionB) positionB else it
} else {
if (it >= 1f) 1f else it
}
}
} else {
(position - delta).let {
if (useAB) {
if (it <= positionA) positionA else it
} else {
if (it <= 0f) 0f else it
}
}
}
}
else -> {
}
}
}
}
) {
val ax = padStart + range * positionA
val bx = padStart + range * positionB
val thumbx = padStart + range * position
if (useAB) {
drawLine(
color = Color(0xfff5f7f9),
start = Offset(padStart, centerVertical),
end = Offset(padStart + range, centerVertical),
strokeWidth = 5f,
cap = StrokeCap.Round
)
drawLine(
brush = Brush.horizontalGradient(
0f to Color(0xffF93685),
1f to Color(0xffFF33F2)
),
start = Offset(ax, centerVertical),
end = Offset(bx, centerVertical),
strokeWidth = 5f,
cap = StrokeCap.Round
)
drawImage(
image = thumb,
dstSize = thumbSize,
dstOffset = IntOffset(
(thumbx - thumbSize.width / 2).toInt(),
(centerVertical - thumbSize.height / 2).toInt()
)
)
drawImage(
image = a,
dstSize = aSize,
dstOffset = IntOffset(
(ax - aSize.width).toInt(),
(centerVertical - aSize.height).toInt()
)
)
drawImage(
image = b,
dstSize = bSize,
dstOffset = IntOffset(
bx.toInt(),
(centerVertical - bSize.height).toInt()
)
)
} else {
drawLine(
color = Color(0xfff5f7f9),
start = Offset(padStart, centerVertical),
end = Offset(padStart + range, centerVertical),
strokeWidth = 5f,
cap = StrokeCap.Round
)
drawLine(
brush = Brush.horizontalGradient(
0f to Color(0xffF93685),
1f to Color(0xffFF33F2)
),
start = Offset(padStart, centerVertical),
end = Offset(thumbx, centerVertical),
strokeWidth = 5f,
cap = StrokeCap.Round
)
drawImage(
image = thumb,
dstSize = thumbSize,
dstOffset = IntOffset(
(thumbx - thumbSize.width / 2).toInt(),
(centerVertical - thumbSize.height / 2).toInt()
)
)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment