FloatingActionButton.kt 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package eu.kanade.presentation.components
  2. import androidx.compose.animation.AnimatedVisibility
  3. import androidx.compose.animation.core.CubicBezierEasing
  4. import androidx.compose.animation.core.animateDpAsState
  5. import androidx.compose.animation.core.tween
  6. import androidx.compose.animation.expandHorizontally
  7. import androidx.compose.animation.fadeIn
  8. import androidx.compose.animation.fadeOut
  9. import androidx.compose.animation.shrinkHorizontally
  10. import androidx.compose.foundation.interaction.MutableInteractionSource
  11. import androidx.compose.foundation.layout.Row
  12. import androidx.compose.foundation.layout.Spacer
  13. import androidx.compose.foundation.layout.padding
  14. import androidx.compose.foundation.layout.sizeIn
  15. import androidx.compose.foundation.layout.width
  16. import androidx.compose.material3.FloatingActionButton
  17. import androidx.compose.material3.FloatingActionButtonDefaults
  18. import androidx.compose.material3.FloatingActionButtonElevation
  19. import androidx.compose.material3.MaterialTheme
  20. import androidx.compose.material3.contentColorFor
  21. import androidx.compose.runtime.Composable
  22. import androidx.compose.runtime.getValue
  23. import androidx.compose.runtime.remember
  24. import androidx.compose.ui.Alignment
  25. import androidx.compose.ui.Modifier
  26. import androidx.compose.ui.graphics.Color
  27. import androidx.compose.ui.graphics.Shape
  28. import androidx.compose.ui.unit.dp
  29. @Composable
  30. fun ExtendedFloatingActionButton(
  31. text: @Composable () -> Unit,
  32. icon: @Composable () -> Unit,
  33. onClick: () -> Unit,
  34. modifier: Modifier = Modifier,
  35. expanded: Boolean = true,
  36. interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
  37. shape: Shape = MaterialTheme.shapes.large,
  38. containerColor: Color = MaterialTheme.colorScheme.primaryContainer,
  39. contentColor: Color = contentColorFor(containerColor),
  40. elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
  41. ) {
  42. val minWidth by animateDpAsState(if (expanded) ExtendedFabMinimumWidth else FabContainerWidth)
  43. FloatingActionButton(
  44. modifier = modifier.sizeIn(minWidth = minWidth),
  45. onClick = onClick,
  46. interactionSource = interactionSource,
  47. shape = shape,
  48. containerColor = containerColor,
  49. contentColor = contentColor,
  50. elevation = elevation,
  51. ) {
  52. val startPadding by animateDpAsState(if (expanded) ExtendedFabIconSize / 2 else 0.dp)
  53. val endPadding by animateDpAsState(if (expanded) ExtendedFabTextPadding else 0.dp)
  54. Row(
  55. modifier = Modifier.padding(start = startPadding, end = endPadding),
  56. verticalAlignment = Alignment.CenterVertically,
  57. ) {
  58. icon()
  59. AnimatedVisibility(
  60. visible = expanded,
  61. enter = ExtendedFabExpandAnimation,
  62. exit = ExtendedFabCollapseAnimation,
  63. ) {
  64. Row {
  65. Spacer(Modifier.width(ExtendedFabIconPadding))
  66. text()
  67. }
  68. }
  69. }
  70. }
  71. }
  72. private val EasingLinearCubicBezier = CubicBezierEasing(0.0f, 0.0f, 1.0f, 1.0f)
  73. private val EasingEmphasizedCubicBezier = CubicBezierEasing(0.2f, 0.0f, 0.0f, 1.0f)
  74. private val ExtendedFabMinimumWidth = 80.dp
  75. private val ExtendedFabIconSize = 24.0.dp
  76. private val ExtendedFabIconPadding = 12.dp
  77. private val ExtendedFabTextPadding = 20.dp
  78. private val ExtendedFabCollapseAnimation = fadeOut(
  79. animationSpec = tween(
  80. durationMillis = 100,
  81. easing = EasingLinearCubicBezier,
  82. ),
  83. ) + shrinkHorizontally(
  84. animationSpec = tween(
  85. durationMillis = 500,
  86. easing = EasingEmphasizedCubicBezier,
  87. ),
  88. shrinkTowards = Alignment.Start,
  89. )
  90. private val ExtendedFabExpandAnimation = fadeIn(
  91. animationSpec = tween(
  92. durationMillis = 200,
  93. delayMillis = 100,
  94. easing = EasingLinearCubicBezier,
  95. ),
  96. ) + expandHorizontally(
  97. animationSpec = tween(
  98. durationMillis = 500,
  99. easing = EasingEmphasizedCubicBezier,
  100. ),
  101. expandFrom = Alignment.Start,
  102. )
  103. private val FabContainerWidth = 56.0.dp