Last active
February 6, 2023 10:11
-
-
Save programmerAbc/d768aaaf449cb301e01c6b9d2e765bda to your computer and use it in GitHub Desktop.
ABSlider
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @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