What You Will Build
A share button that reveals social sharing options (Email, Message, Copy, More) with staggered scale-in animations when tapped. Each option appears as a colored circle with an icon and label. Tapping the button again or selecting an option collapses the row back.
Why This Pattern Matters
Rather than launching the system share sheet immediately, an in-app share row gives users quick access to the most common sharing channels. The staggered animation makes each option feel individually introduced, creating a premium interaction feel.
The Complete Share Button
@Composable
fun ShareButtonScreen() {
var expanded by remember { mutableStateOf(false) }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// Share options row
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
data class ShareOption(
val icon: ImageVector,
val name: String,
val color: Color
)
val options = listOf(
ShareOption(Icons.Default.Email, "Email", Color(0xFFEA4335)),
ShareOption(Icons.Default.Chat, "Message", Color(0xFF4CAF50)),
ShareOption(Icons.Default.ContentCopy, "Copy", Color(0xFF2196F3)),
ShareOption(Icons.Default.MoreHoriz, "More", Color(0xFF9E9E9E))
)
options.forEachIndexed { index, option ->
val scale by animateFloatAsState(
targetValue = if (expanded) 1f else 0f,
animationSpec = tween(250, delayMillis = index * 60),
label = "scale_$index"
)
if (expanded && scale > 0.01f) {
Column(
modifier = Modifier.scale(scale),
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.size(52.dp)
.background(option.color, CircleShape)
.clickable { expanded = false },
contentAlignment = Alignment.Center
) {
Icon(option.icon, option.name,
tint = Color.White,
modifier = Modifier.size(24.dp))
}
Spacer(modifier = Modifier.height(4.dp))
Text(option.name, fontSize = 11.sp, color = Color.Gray)
}
}
}
}
Spacer(modifier = Modifier.height(24.dp))
// Main share trigger button
Box(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(Color(0xFF2196F3))
.clickable { expanded = !expanded }
.padding(horizontal = 32.dp, vertical = 14.dp),
contentAlignment = Alignment.Center
) {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Default.Share, null, tint = Color.White)
Text(
if (expanded) "Close" else "Share",
color = Color.White,
fontWeight = FontWeight.Bold
)
}
}
}
}
Tips and Pitfalls
- Staggered delay of 60ms per index creates a wave-like reveal. Too fast (under 30ms) and they appear simultaneously; too slow (over 150ms) and it feels sluggish.
- Check scale > 0.01f to avoid composing invisible items during the collapse animation.
- Button text toggles between "Share" and "Close" to give clear affordance about the current state.
- For production: Wire each option's onClick to
Intent.ACTION_SEND, clipboard manager, or your deep link sharing logic.