bernaferrari/diagonal-wipe-icon
A one-file icon transition component for Compose
π What Is This?
Apple's SF Symbols makes it easy to add wipe icon transitions to iOS apps. In Compose, achieving this built-in behavior is tediousβit often requires creating animated drawables manually or relying on third-party editors every single time.
Diagonal Wipe Icon bridges this gap. It provides a polished component that emulates this behavior using two standard icons and a mask. Perfect for:
- ποΈ Toggle controls (
on/off,enabled/disabled,visible/hidden) - βοΈ Settings screens with stateful icons
- β¨ Anywhere you want polished micro-interactions
Zero dependencies. Just copy a single file.
οΏ½ Quick Start
Grab the file:
curl -O https://raw.githubusercontent.com/bernaferrari/diagonal-wipe-icon/main/composeApp/src/commonMain/kotlin/com/bernaferrari/diagonalwipeicon/DiagonalWipeIcon.ktDrop it into your commonMain/kotlin folder, and wrap it in your preferred click listener:
@Composable
fun FavoriteButton() {
var isFavorite by remember { mutableStateOf(false) }
IconButton(onClick = { isFavorite = !isFavorite }) {
DiagonalWipeIcon(
isWiped = !isFavorite,
baseIcon = Icons.Outlined.Favorite,
wipedIcon = Icons.Outlined.FavoriteBorder,
contentDescription = "Favorite Toggle"
)
}
}π¨ Customization
You can deeply customize the transition feel using motion parameter or custom Painters.
DiagonalWipeIcon(
// State and Icons
isWiped = isMuted,
baseIcon = Icons.Outlined.VolumeUp,
wipedIcon = Icons.Outlined.VolumeOff,
// Optional Colors
baseTint = Color.Unspecified,
wipedTint = Color.Unspecified,
// Motion Presets
motion = DiagonalWipeIconDefaults.gentle() // default, smooth feel
// motion = DiagonalWipeIconDefaults.snappy() // fast and responsive feel
// motion = DiagonalWipeIconDefaults.gentle(direction = WipeDirection.TopToBottom) // 8 cardinal/diagonal directions supported
// motion = DiagonalWipeIconDefaults.spring(wipeInStiffness = Spring.StiffnessLow) // organic, physics-based motion
)Note: Overloads exist for both ImageVector and Painter.
β‘ Performance & Under The Hood
A moving clip path reveals one icon while concealing the other through smooth interpolations over 8 supported directions.
| Scenario | Performance |
|---|---|
At Rest (isWiped settled) |
Same as rendering a single static icon. |
| During Transition | ~2x cost (rendering two layers + dynamic clip path). |
| Normal Usage (5-10 icons) | Flawless and smooth on modern devices. |
- β Settled states bypass compositing entirely
- β Tint filters cached and reused
- β Path buffers pooled across frames
β FAQ
- Can I use my own icons? Yes. Any
ImageVectororPainter. - Does it work on iOS? Yes, it works seamlessly in Compose Multiplatform
commonMain. - What about accessibility? Pass
contentDescriptionand it respects semantics. - Run the Demo Locally:
- Web:
./gradlew :composeApp:jsBrowserDevelopmentRun - Android:
./gradlew :androidApp:installDebug
- Web:
π License
MIT Β© Bernardo Ferrari