Bubble Button

Bubble Button

Subscribe for Live Previews, in your browser

$3 / month

Code

import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.spring
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.dropShadow
import androidx.compose.ui.draw.innerShadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Color.Companion.Transparent
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.PointerIcon
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp
import theme.Colors
import theme.Colors.Zinc100
import theme.Colors.Zinc300

@Composable
fun BubbleButtonImpl(modifier: Modifier = Modifier) {
    Box(
        modifier = modifier
            .fillMaxSize()
            .background(Colors.Pink400),
        contentAlignment = Alignment.Center
    ) {
        BubbleButton(
            onClick = {

            }
        ) {
            Text(
                "Bubble Button",
                color = Color.White
            )
        }
    }
}

@Composable
fun BubbleButton(
    modifier: Modifier = Modifier,
    onClick: () -> Unit,
    shape: Shape = RoundedCornerShape(16.dp),
    content: @Composable RowScope.() -> Unit,
) {
    var isPressed by remember { mutableStateOf(false) }
    val scale by animateFloatAsState(
        targetValue = if (isPressed) .85f else 1f,
        animationSpec = if (isPressed)
            spring(
                dampingRatio = Spring.DampingRatioMediumBouncy,
                stiffness = Spring.StiffnessMediumLow
            )
        else
            spring(
                stiffness = Spring.StiffnessLow,
                dampingRatio = Spring.DampingRatioHighBouncy,
            ),
        visibilityThreshold = .000001f
    )
    Row(
        modifier = modifier
            .pointerInput(Unit) {
                detectTapGestures(
                    onPress = {
                        isPressed = true
                        tryAwaitRelease()
                        isPressed = false
                    },
                    onTap = {
                        onClick()
                    }
                )
            }
            .pointerHoverIcon(PointerIcon.Hand)
            .graphicsLayer {
                scaleY = scale
                scaleX = (1f - scale) + 1f
            }
            .dropShadow(
                shape = shape
            ) {
                radius = 80f
                alpha = .2f
            }
            .border(
                width = 0.dp,
                shape = shape,
                brush = Brush.verticalGradient(
                    colors = listOf(
                        Color.White,
                        Zinc300,
                    )
                ),
            )
            .innerShadow(
                shape = shape
            ) {
                radius = 40f
                brush = Brush.verticalGradient(
                    colors = listOf(
                        Zinc100,
                        Zinc100,
                    )
                )
                alpha = .4f
            }
            .innerShadow(
                shape = shape
            ) {
                radius = 30f
                spread = 1f
                brush = Brush.verticalGradient(
                    colors = listOf(
                        Color.White,
                        Transparent,
                        Transparent,
                    )
                )
                alpha = .8f
            }
            .innerShadow(
                shape = shape
            ) {
                radius = 80f
                spread = 1f
                brush = Brush.verticalGradient(
                    colors = listOf(
                        Color.White,
                        Transparent,
                        Transparent,
                    )
                )
                alpha = .5f
            }
            .innerShadow(
                shape = shape
            ) {
                radius = 40f
                spread = 1f
                brush = Brush.linearGradient(
                    colors = listOf(
                        Colors.Transparent,
                        Colors.Rose500,
                        Colors.Violet500,
                    )
                )
                alpha = .5f
            }
            .padding(horizontal = 32.dp, vertical = 16.dp)
    ) {
        content()
    }
}
Mastodon