
Tactile rubber-band drag interaction for text labels, with physics-based spring animation, shared drag/display state, three-way crossfade, configurable resistance and bounce.
Give your Compose UI some snap. Why settle for static text when you can have text that
stretches? RubberTextView is a lightweight Jetpack Compose library that brings a tactile,
rubber-band interaction to your labels. Drag to reveal new values, let go to watch them spring back.
It’s perfect for value pickers, playful navigation, or just giving your users something satisfying to fidget with.
androidx.compose.animation.core.spring for that natural,
non-linear feel.start, center, and end labels based on
drag intensity.RubberTextView works by splitting the interaction into three simple parts:
RubberDragState: The brain. It tracks the offset and handles the spring physics.RubberDragBox: The muscle. This is the invisible (or visible!) surface that catches the
user's thumb.RubberTextView: The face. This renders your labels and handles the crossfading magic.Getting that "squishy" feel into your app is a four-step process:
Create a rememberRubberDragState. You can tweak the dampingRatio and stiffness here to make it
feel "tight" or "loose."
Place a RubberDragBox in your layout. This defines the area where the user can actually drag.
Inside (or even outside) that box, add the RubberTextView and pass it your labels.
Run your app and enjoy the springy goodness.
@Composable
fun MySpringyUI() {
// 1. Create the state
val state = rememberRubberDragState(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
)
Column {
// 2. The Display
RubberTextView(
modifier = Modifier.fillMaxWidth().padding(20.dp),
startLabel = "Less",
label = "Just Right",
endLabel = "More",
state = state
)
// 3. The Interactive Surface
RubberDragBox(
modifier = Modifier.fillMaxWidth().height(200.dp).background(Color.LightGray),
state = state
) {
Text("Drag me horizontally!", Modifier.align(Alignment.Center))
}
}
}You have full control over the "tension" of the rubber band:
| Parameter | Description | Values | Default |
|---|---|---|---|
resistance |
How much the drag "resists" the finger (default 0.4f). |
Float | 0.4f |
dampingRatio |
Controls the bounciness (e.g., Bouncy vs NoBouncy). |
DampingRatioHighBouncy, DampingRatioMediumBouncy, DampingRatioLowBouncy, DampingRatioNoBouncy | DampingRatioMediumBouncy |
stiffness |
How fast the text snaps back to the center. | StiffnessHigh, StiffnessMedium, StiffnessMediumLow, StiffnessLow, StiffnessVeryLow | StiffnessMedium |
fadeThresholdDivisor |
Adjusts how quickly the side labels fade in during a drag. | Float | 2.5f |
Got an idea to make it even stretchier? Maybe vertical dragging or multi-label support? Pull requests are always welcome!
Give your Compose UI some snap. Why settle for static text when you can have text that
stretches? RubberTextView is a lightweight Jetpack Compose library that brings a tactile,
rubber-band interaction to your labels. Drag to reveal new values, let go to watch them spring back.
It’s perfect for value pickers, playful navigation, or just giving your users something satisfying to fidget with.
androidx.compose.animation.core.spring for that natural,
non-linear feel.start, center, and end labels based on
drag intensity.RubberTextView works by splitting the interaction into three simple parts:
RubberDragState: The brain. It tracks the offset and handles the spring physics.RubberDragBox: The muscle. This is the invisible (or visible!) surface that catches the
user's thumb.RubberTextView: The face. This renders your labels and handles the crossfading magic.Getting that "squishy" feel into your app is a four-step process:
Create a rememberRubberDragState. You can tweak the dampingRatio and stiffness here to make it
feel "tight" or "loose."
Place a RubberDragBox in your layout. This defines the area where the user can actually drag.
Inside (or even outside) that box, add the RubberTextView and pass it your labels.
Run your app and enjoy the springy goodness.
@Composable
fun MySpringyUI() {
// 1. Create the state
val state = rememberRubberDragState(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
)
Column {
// 2. The Display
RubberTextView(
modifier = Modifier.fillMaxWidth().padding(20.dp),
startLabel = "Less",
label = "Just Right",
endLabel = "More",
state = state
)
// 3. The Interactive Surface
RubberDragBox(
modifier = Modifier.fillMaxWidth().height(200.dp).background(Color.LightGray),
state = state
) {
Text("Drag me horizontally!", Modifier.align(Alignment.Center))
}
}
}You have full control over the "tension" of the rubber band:
| Parameter | Description | Values | Default |
|---|---|---|---|
resistance |
How much the drag "resists" the finger (default 0.4f). |
Float | 0.4f |
dampingRatio |
Controls the bounciness (e.g., Bouncy vs NoBouncy). |
DampingRatioHighBouncy, DampingRatioMediumBouncy, DampingRatioLowBouncy, DampingRatioNoBouncy | DampingRatioMediumBouncy |
stiffness |
How fast the text snaps back to the center. | StiffnessHigh, StiffnessMedium, StiffnessMediumLow, StiffnessLow, StiffnessVeryLow | StiffnessMedium |
fadeThresholdDivisor |
Adjusts how quickly the side labels fade in during a drag. | Float | 2.5f |
Got an idea to make it even stretchier? Maybe vertical dragging or multi-label support? Pull requests are always welcome!