Skip to content

Instantly share code, notes, and snippets.

@anitaa1990
Last active April 9, 2025 19:53
Show Gist options
  • Save anitaa1990/b687344c083275c78ae9f022cc2c2341 to your computer and use it in GitHub Desktop.
Save anitaa1990/b687344c083275c78ae9f022cc2c2341 to your computer and use it in GitHub Desktop.
@Composable
fun SlideToBookButton(
btnText: String,
btnTextStyle: TextStyle,
outerBtnBackgroundColor: Color,
sliderBtnBackgroundColor: Color,
@DrawableRes sliderBtnIcon: Int,
onBtnSwipe: () -> Unit
) {
// Slider button width
val sliderButtonWidthDp = 70.dp
/**
* ----------------------------------------
* ✨ Step 1:
* • Convert slider button width into pixels so we can use it in math
* • Define a variable to compute the current horizontal position of the slider button (in pixels)
* • Define a variable to capture the total width of the outer button in pixels
* ----------------------------------------
*/
val density = LocalDensity.current
val sliderButtonWidthPx = with(density) { sliderButtonWidthDp.toPx() }
var sliderPositionPx by remember { mutableFloatStateOf(0f) }
var boxWidthPx by remember { mutableIntStateOf(0) }
/**
* ----------------------------------------
* ✨ Step 5: Calculate drag progress percentage (0f to 1f)
* ----------------------------------------
*/
val dragProgress = remember(sliderPositionPx, boxWidthPx) {
if (boxWidthPx > 0) {
(sliderPositionPx / (boxWidthPx - sliderButtonWidthPx)).coerceIn(0f, 1f)
} else {
0f
}
}
/**
* ----------------------------------------
* ✨ Step 6: Alpha value for the button label — 1 when untouched, fades to 0 as drag progresses
* ----------------------------------------
*/
val textAlpha = 1f - dragProgress
// The root layout for the button — stretches full width and has fixed height
Box(
modifier = Modifier
.fillMaxWidth()
.height(55.dp)
/**
* ----------------------------------------
* ✨ Step 2: Capture the full width of the button once it's laid out
* ----------------------------------------
*/
.onSizeChanged { size ->
boxWidthPx = size.width
}
) {
// Outer track — acts as the base of the button
Box(
modifier = Modifier
.matchParentSize()
.background(
color = outerBtnBackgroundColor,
shape = RoundedCornerShape(12.dp)
)
) {
// The center-aligned button label
Text(
text = btnText,
style = btnTextStyle,
modifier = Modifier.align(Alignment.Center)
/**
* ----------------------------------------
* ✨ Step 7: Apply the dynamic transparency to the label
* ----------------------------------------
*/
.alpha(textAlpha)
)
}
// Slider thumb container, positioned at the left edge of the button
Row(
modifier = Modifier
.align(Alignment.CenterStart)
.padding(1.dp)
/**
* ----------------------------------------
* ✨ Step 3: Shift the slider button based on drag position (px to dp conversion)
* ----------------------------------------
*/
.offset(x = with(density) { sliderPositionPx.toDp() })
/**
* ----------------------------------------
* ✨ Step 4: Handle horizontal drag gestures
* ----------------------------------------
*/
.draggable(
orientation = Orientation.Horizontal,
state = rememberDraggableState { delta ->
// Calculate new potential position
val newPosition = sliderPositionPx + delta
// Clamp it within 0 to (totalWidth - slider button width)
val maxPosition = boxWidthPx - sliderButtonWidthPx
sliderPositionPx = newPosition.coerceIn(0f, maxPosition)
},
onDragStarted = { /* Optional: add feedback or animation here */ },
onDragStopped = { }
),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
) {
// The draggable thumb itself
SliderButton(
sliderBtnWidth = sliderButtonWidthDp,
sliderBtnBackgroundColor = sliderBtnBackgroundColor,
sliderBtnIcon = sliderBtnIcon
)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment