Last active
May 28, 2024 11:14
-
-
Save c5inco/38e5075a883e5cc1136308bd3c44686d to your computer and use it in GitHub Desktop.
Jetpack Compose implementation of inspirational design https://twitter.com/philipcdavis/status/1486871621600104450
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package des.c5inco.material3 | |
import androidx.compose.animation.* | |
import androidx.compose.animation.core.* | |
import androidx.compose.foundation.background | |
import androidx.compose.foundation.clickable | |
import androidx.compose.foundation.interaction.MutableInteractionSource | |
import androidx.compose.foundation.layout.* | |
import androidx.compose.foundation.shape.CircleShape | |
import androidx.compose.foundation.shape.RoundedCornerShape | |
import androidx.compose.material.icons.Icons | |
import androidx.compose.material.icons.filled.StopCircle | |
import androidx.compose.material.icons.outlined.* | |
import androidx.compose.material3.Icon | |
import androidx.compose.material3.MaterialTheme | |
import androidx.compose.material3.Surface | |
import androidx.compose.runtime.* | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.graphics.Brush | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.graphics.graphicsLayer | |
import androidx.compose.ui.tooling.preview.Preview | |
import androidx.compose.ui.unit.dp | |
@ExperimentalAnimationApi | |
@Composable | |
fun CollapsingTabBar( | |
modifier: Modifier = Modifier | |
) { | |
var expanded by remember { mutableStateOf(false) } | |
AnimatedContent( | |
targetState = expanded, | |
transitionSpec = { | |
if (targetState) { | |
fadeIn(animationSpec = tween(700)) with | |
fadeOut(animationSpec = tween(300)) + | |
scaleOut(targetScale = 0.8f, animationSpec = tween(300)) | |
} else { | |
fadeIn(animationSpec = tween(300)) + | |
scaleIn(initialScale = 0.8f, animationSpec = tween(300)) with | |
fadeOut(animationSpec = tween(500)) | |
}.using(SizeTransform(sizeAnimationSpec = { _, _ -> | |
tween(600) | |
})) | |
}, | |
contentAlignment = Alignment.Center, | |
modifier = modifier | |
.background( | |
color = Color.Black.copy(alpha = 0.7f), | |
shape = RoundedCornerShape(percent = 100) | |
) | |
.clickable( | |
interactionSource = remember { MutableInteractionSource() }, | |
indication = null, | |
onClick = { expanded = !expanded } | |
) | |
) { targetExpanded -> | |
if (!targetExpanded) { | |
Box(contentAlignment = Alignment.Center) { | |
val infiniteTransition = rememberInfiniteTransition() | |
val size by infiniteTransition.animateFloat( | |
initialValue = 40f, | |
targetValue = 72f, | |
animationSpec = infiniteRepeatable( | |
animation = tween(3000, easing = FastOutSlowInEasing), | |
repeatMode = RepeatMode.Restart | |
) | |
) | |
val animatedAlpha by infiniteTransition.animateFloat( | |
initialValue = 1f, | |
targetValue = 0f, | |
animationSpec = infiniteRepeatable( | |
animation = tween(3000), | |
repeatMode = RepeatMode.Restart | |
) | |
) | |
Box(Modifier | |
.size(size.dp) | |
.graphicsLayer { alpha = animatedAlpha } | |
.background( | |
brush = Brush.radialGradient( | |
0.4f to Color.Red.copy(alpha = 0f), | |
0.6f to Color.Red.copy(alpha = 0.5f), | |
1.0f to Color.Red, | |
), | |
shape = CircleShape | |
) | |
) | |
Box(modifier = Modifier.padding(12.dp)) { | |
Icon( | |
imageVector = Icons.Default.StopCircle, | |
contentDescription = null, | |
modifier = Modifier.size(48.dp), | |
tint = Color.Red | |
) | |
} | |
} | |
} else { | |
val icons = listOf( | |
Icons.Outlined.Backspace, | |
Icons.Outlined.Keyboard, | |
Icons.Outlined.GraphicEq, | |
Icons.Outlined.Camera, | |
Icons.Outlined.Share | |
) | |
Row( | |
modifier = Modifier.padding(horizontal = 36.dp, vertical = 18.dp), | |
horizontalArrangement = Arrangement.spacedBy(20.dp) | |
) { | |
icons.forEach { icon -> | |
Icon( | |
imageVector = icon, | |
contentDescription = null, | |
modifier = Modifier.size(36.dp), | |
tint = Color.White | |
) | |
} | |
} | |
} | |
} | |
} | |
@ExperimentalAnimationApi | |
@Preview(showBackground = true) | |
@Composable | |
fun CollapsingTabBarPreview() { | |
MaterialTheme { | |
Surface(Modifier.fillMaxSize()) { | |
Box { | |
CollapsingTabBar( | |
Modifier | |
.padding(bottom = 32.dp) | |
.align(Alignment.BottomCenter) | |
) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment