Skip to content

delacrixmorgan/rubbertextview-kmp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ€ RubberTextView

Maven Central Version

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.

Overview


✨ Features

  • Shared State Logic: Separate your gesture area from your display area.
  • Physics-Based: Built on top of androidx.compose.animation.core.spring for that natural, non-linear feel.
  • Three-Way Crossfade: Smoothly transition between start, center, and end labels based on drag intensity.
  • Customizable Resistance: Control how hard your users have to "pull" to see the hidden labels.

πŸ“¦ Installation

Add the dependency to your build.gradle.kts:

implementation("com.dontsaybojio:rubbertextview:X.X.X")

Make sure mavenCentral() is in your repository list:

repositories {
    mavenCentral()
}

πŸš€ How It Works

RubberTextView works by splitting the interaction into three simple parts:

  1. RubberDragState: The brain. It tracks the offset and handles the spring physics.
  2. RubberDragBox: The muscle. This is the invisible (or visible!) surface that catches the user's thumb.
  3. RubberTextView: The face. This renders your labels and handles the crossfading magic.

πŸ›  Usage

Getting that "squishy" feel into your app is a four-step process:

  1. Initialize the State

Create a rememberRubberDragState. You can tweak the dampingRatio and stiffness here to make it feel "tight" or "loose."

  1. Wrap your content in a DragBox

Place a RubberDragBox in your layout. This defines the area where the user can actually drag.

  1. Add the TextView

Inside (or even outside) that box, add the RubberTextView and pass it your labels.

  1. Sit back and stretch

Run your app and enjoy the springy goodness.

Quick Example

@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,
            onDragCompleted = { direction ->
                println("Drag completed: $direction") // RubberDragDirection.Left or .Right
            }
        ) {
            Text("Drag me horizontally!", Modifier.align(Alignment.Center))
        }
    }
}

🎨 Customization

You have full control over the "tension" of the rubber band:

rememberRubberDragState

Parameter Description Values Default
resistance How much the drag "resists" the finger. 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

RubberTextView

Parameter Description Values Default
fadeThresholdDivisor Adjusts how quickly the side labels fade in during a drag. Float 2.5f

RubberDragBox

Parameter Description Values Default
enabled When false, the horizontal drag gesture is disabled and onDragCompleted is never invoked. Content is still rendered normally. Boolean true
onDragCompleted Optional callback invoked when the drag ends and the offset exceeds dragThreshold. Receives RubberDragDirection.Left or RubberDragDirection.Right. Not called below threshold. ((RubberDragDirection) -> Unit)? null
dragThreshold Minimum absolute offset that must be reached for onDragCompleted to fire. Float 85f

🀝 Contributing

Got an idea to make it even stretchier? Maybe vertical dragging or multi-label support? Pull requests are always welcome!