Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.material3
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandHorizontally
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.foundation.interaction.FocusInteraction
import androidx.compose.foundation.interaction.HoverInteraction
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.width
import androidx.compose.material3.tokens.ExtendedFabPrimaryTokens
import androidx.compose.material3.tokens.FabPrimaryLargeTokens
import androidx.compose.material3.tokens.FabPrimarySmallTokens
import androidx.compose.material3.tokens.FabPrimaryTokens
import androidx.compose.material3.tokens.MotionTokens
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
/**
* Material Design floating action button.
*
* The FAB represents the most important action on a screen. It puts key actions within reach.
*
* ![FAB image](https://developer.android.com/images/reference/androidx/compose/material3/fab.png)
*
* FAB typically contains an icon, for a FAB with text and an icon, see
* [ExtendedFloatingActionButton].
*
* @sample androidx.compose.material3.samples.FloatingActionButtonSample
*
* @param onClick called when this FAB is clicked
* @param modifier the [Modifier] to be applied to this FAB
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this FAB. You can create and pass in your own `remember`ed instance to observe [Interaction]s
* and customize the appearance / behavior of this FAB in different states.
* @param shape defines the shape of this FAB's container and shadow (when using [elevation])
* @param containerColor the color used for the background of this FAB. Use [Color.Transparent] to
* have no color.
* @param contentColor the preferred color for content inside this FAB. Defaults to either the
* matching content color for [containerColor], or to the current [LocalContentColor] if
* [containerColor] is not a color from the theme.
* @param elevation [FloatingActionButtonElevation] used to resolve the elevation for this FAB in
* different states. This controls the size of the shadow below the FAB. Additionally, when the
* container color is [ColorScheme.surface], this controls the amount of primary color applied as an
* overlay. See also: [Surface].
* @param content the content of this FAB, typically an [Icon]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = FloatingActionButtonDefaults.Shape,
containerColor: Color = FloatingActionButtonDefaults.ContainerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
content: @Composable () -> Unit,
) {
Surface(
onClick = onClick,
modifier = modifier,
shape = shape,
color = containerColor,
contentColor = contentColor,
tonalElevation = elevation.tonalElevation(interactionSource = interactionSource).value,
shadowElevation = elevation.shadowElevation(interactionSource = interactionSource).value,
interactionSource = interactionSource,
) {
CompositionLocalProvider(LocalContentColor provides contentColor) {
// Adding the text style from [ExtendedFloatingActionButton] to all FAB variations. In
// the majority of cases this will have no impact, because icons are expected, but if a
// developer decides to put some short text to emulate an icon, (like "?") then it will
// have the correct styling.
ProvideTextStyle(
MaterialTheme.typography.fromToken(ExtendedFabPrimaryTokens.LabelTextFont),
) {
Box(
modifier = Modifier
.defaultMinSize(
minWidth = FabPrimaryTokens.ContainerWidth,
minHeight = FabPrimaryTokens.ContainerHeight,
),
contentAlignment = Alignment.Center,
) { content() }
}
}
}
}
/**
* Material Design small floating action button.
*
* The FAB represents the most important action on a screen. It puts key actions within reach.
*
* ![Small FAB image](https://developer.android.com/images/reference/androidx/compose/material3/small-fab.png)
*
* @sample androidx.compose.material3.samples.SmallFloatingActionButtonSample
*
* @param onClick called when this FAB is clicked
* @param modifier the [Modifier] to be applied to this FAB
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this FAB. You can create and pass in your own `remember`ed instance to observe [Interaction]s
* and customize the appearance / behavior of this FAB in different states.
* @param shape defines the shape of this FAB's container and shadow (when using [elevation])
* @param containerColor the color used for the background of this FAB. Use [Color.Transparent] to
* have no color.
* @param contentColor the preferred color for content inside this FAB. Defaults to either the
* matching content color for [containerColor], or to the current [LocalContentColor] if
* [containerColor] is not a color from the theme.
* @param elevation [FloatingActionButtonElevation] used to resolve the elevation for this FAB in
* different states. This controls the size of the shadow below the FAB. Additionally, when the
* container color is [ColorScheme.surface], this controls the amount of primary color applied as an
* overlay. See also: [Surface].
* @param content the content of this FAB, typically an [Icon]
*/
@Composable
fun SmallFloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = FloatingActionButtonDefaults.SmallShape,
containerColor: Color = FloatingActionButtonDefaults.ContainerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
content: @Composable () -> Unit,
) {
FloatingActionButton(
onClick = onClick,
modifier = modifier.sizeIn(
minWidth = FabPrimarySmallTokens.ContainerWidth,
minHeight = FabPrimarySmallTokens.ContainerHeight,
),
interactionSource = interactionSource,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
content = content,
)
}
/**
* Material Design large floating action button.
*
* The FAB represents the most important action on a screen. It puts key actions within reach.
*
* ![Large FAB image](https://developer.android.com/images/reference/androidx/compose/material3/large-fab.png)
*
* @sample androidx.compose.material3.samples.LargeFloatingActionButtonSample
*
* @param onClick called when this FAB is clicked
* @param modifier the [Modifier] to be applied to this FAB
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this FAB. You can create and pass in your own `remember`ed instance to observe [Interaction]s
* and customize the appearance / behavior of this FAB in different states.
* @param shape defines the shape of this FAB's container and shadow (when using [elevation])
* @param containerColor the color used for the background of this FAB. Use [Color.Transparent] to
* have no color.
* @param contentColor the preferred color for content inside this FAB. Defaults to either the
* matching content color for [containerColor], or to the current [LocalContentColor] if
* [containerColor] is not a color from the theme.
* @param elevation [FloatingActionButtonElevation] used to resolve the elevation for this FAB in
* different states. This controls the size of the shadow below the FAB. Additionally, when the
* container color is [ColorScheme.surface], this controls the amount of primary color applied as an
* overlay. See also: [Surface].
* @param content the content of this FAB, typically an [Icon]
*/
@Composable
fun LargeFloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = FloatingActionButtonDefaults.LargeShape,
containerColor: Color = FloatingActionButtonDefaults.ContainerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
content: @Composable () -> Unit,
) {
FloatingActionButton(
onClick = onClick,
modifier = modifier.sizeIn(
minWidth = FabPrimaryLargeTokens.ContainerWidth,
minHeight = FabPrimaryLargeTokens.ContainerHeight,
),
interactionSource = interactionSource,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
content = content,
)
}
/**
* Material Design extended floating action button.
*
* Extended FABs help people take primary actions. They're wider than FABs to accommodate a text
* label and larger target area.
*
* ![Extended FAB image](https://developer.android.com/images/reference/androidx/compose/material3/extended-fab.png)
*
* The other extended floating action button overload supports a text label and icon.
*
* @sample androidx.compose.material3.samples.ExtendedFloatingActionButtonTextSample
*
* @param onClick called when this FAB is clicked
* @param modifier the [Modifier] to be applied to this FAB
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this FAB. You can create and pass in your own `remember`ed instance to observe [Interaction]s
* and customize the appearance / behavior of this FAB in different states.
* @param shape defines the shape of this FAB's container and shadow (when using [elevation])
* @param containerColor the color used for the background of this FAB. Use [Color.Transparent] to
* have no color.
* @param contentColor the preferred color for content inside this FAB. Defaults to either the
* matching content color for [containerColor], or to the current [LocalContentColor] if
* [containerColor] is not a color from the theme.
* @param elevation [FloatingActionButtonElevation] used to resolve the elevation for this FAB in
* different states. This controls the size of the shadow below the FAB. Additionally, when the
* container color is [ColorScheme.surface], this controls the amount of primary color applied as an
* overlay. See also: [Surface].
* @param content the content of this FAB, typically a [Text] label
*/
@Composable
fun ExtendedFloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = FloatingActionButtonDefaults.ExtendedFabShape,
containerColor: Color = FloatingActionButtonDefaults.ContainerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
content: @Composable RowScope.() -> Unit,
) {
FloatingActionButton(
modifier = modifier,
onClick = onClick,
interactionSource = interactionSource,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
) {
Row(
modifier = Modifier
.sizeIn(minWidth = ExtendedFabMinimumWidth)
.padding(horizontal = ExtendedFabTextPadding),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content,
)
}
}
/**
* Material Design extended floating action button.
*
* Extended FABs help people take primary actions. They're wider than FABs to accommodate a text
* label and larger target area.
*
* ![Extended FAB image](https://developer.android.com/images/reference/androidx/compose/material3/extended-fab.png)
*
* The other extended floating action button overload is for FABs without an icon.
*
* @sample androidx.compose.material3.samples.ExtendedFloatingActionButtonSample
* @sample androidx.compose.material3.samples.AnimatedExtendedFloatingActionButtonSample
*
* @param text label displayed inside this FAB
* @param icon optional icon for this FAB, typically an [Icon]
* @param onClick called when this FAB is clicked
* @param modifier the [Modifier] to be applied to this FAB
* @param expanded controls the expansion state of this FAB. In an expanded state, the FAB will show
* both the [icon] and [text]. In a collapsed state, the FAB will show only the [icon].
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this FAB. You can create and pass in your own `remember`ed instance to observe [Interaction]s
* and customize the appearance / behavior of this FAB in different states.
* @param shape defines the shape of this FAB's container and shadow (when using [elevation])
* @param containerColor the color used for the background of this FAB. Use [Color.Transparent] to
* have no color.
* @param contentColor the preferred color for content inside this FAB. Defaults to either the
* matching content color for [containerColor], or to the current [LocalContentColor] if
* [containerColor] is not a color from the theme.
* @param elevation [FloatingActionButtonElevation] used to resolve the elevation for this FAB in
* different states. This controls the size of the shadow below the FAB. Additionally, when the
* container color is [ColorScheme.surface], this controls the amount of primary color applied as an
* overlay. See also: [Surface].
*/
@Composable
fun ExtendedFloatingActionButton(
text: @Composable () -> Unit,
icon: @Composable () -> Unit,
onClick: () -> Unit,
modifier: Modifier = Modifier,
expanded: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = FloatingActionButtonDefaults.ExtendedFabShape,
containerColor: Color = FloatingActionButtonDefaults.ContainerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
) {
FloatingActionButton(
modifier = modifier,
onClick = onClick,
interactionSource = interactionSource,
shape = shape,
containerColor = containerColor,
contentColor = contentColor,
elevation = elevation,
) {
val startPadding = if (expanded) ExtendedFabStartIconPadding else 0.dp
val endPadding = if (expanded) ExtendedFabTextPadding else 0.dp
Row(
modifier = Modifier
.sizeIn(
minWidth = if (expanded) ExtendedFabMinimumWidth
else FabPrimaryTokens.ContainerWidth
)
.padding(start = startPadding, end = endPadding),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = if (expanded) Arrangement.Start else Arrangement.Center
) {
icon()
AnimatedVisibility(
visible = expanded,
enter = ExtendedFabExpandAnimation,
exit = ExtendedFabCollapseAnimation,
) {
Row {
Spacer(Modifier.width(ExtendedFabEndIconPadding))
text()
}
}
}
}
}
/**
* Represents the tonal and shadow elevation for a floating action button in different states.
*
* See [FloatingActionButtonDefaults.elevation] for the default elevation used in a
* [FloatingActionButton] and [ExtendedFloatingActionButton].
*/
@Stable
interface FloatingActionButtonElevation {
/**
* Represents the tonal elevation used in a floating action button, depending on
* [interactionSource]. This should typically be the same value as the [shadowElevation].
*
* Tonal elevation is used to apply a color shift to the surface to give the it higher emphasis.
* When surface's color is [ColorScheme.surface], a higher the elevation will result in a darker
* color in light theme and lighter color in dark theme.
*
* See [shadowElevation] which controls the elevation of the shadow drawn around the FAB.
*
* @param interactionSource the [InteractionSource] for this floating action button
*/
@Composable
fun tonalElevation(interactionSource: InteractionSource): State
/**
* Represents the shadow elevation used in a floating action button, depending on
* [interactionSource]. This should typically be the same value as the [tonalElevation].
*
* Shadow elevation is used to apply a shadow around the FAB to give it higher emphasis.
*
* See [tonalElevation] which controls the elevation with a color shift to the surface.
*
* @param interactionSource the [InteractionSource] for this floating action button
*/
@Composable
fun shadowElevation(interactionSource: InteractionSource): State
}
/**
* Contains the default values used by [FloatingActionButton]
*/
object FloatingActionButtonDefaults {
/** Default shape for a floating action button. */
val Shape: Shape @Composable get() = FabPrimaryTokens.ContainerShape.toShape()
/** Default shape for a small floating action button. */
val SmallShape: Shape @Composable get() = FabPrimarySmallTokens.ContainerShape.toShape()
/** Default shape for a large floating action button. */
val LargeShape: Shape @Composable get() = FabPrimaryLargeTokens.ContainerShape.toShape()
/** Default shape for an extended floating action button. */
val ExtendedFabShape: Shape @Composable get() =
ExtendedFabPrimaryTokens.ContainerShape.toShape()
/** Default container color for a floating action button. */
val ContainerColor: Color @Composable get() = FabPrimaryTokens.ContainerColor.toColor()
/**
* The recommended size of the icon inside a [LargeFloatingActionButton].
*/
val LargeIconSize = FabPrimaryLargeTokens.IconSize
/**
* Creates a [FloatingActionButtonElevation] that represents the elevation of a
* [FloatingActionButton] in different states. For use cases in which a less prominent
* [FloatingActionButton] is possible consider the [loweredElevation].
*
* @param defaultElevation the elevation used when the [FloatingActionButton] has no other
* [Interaction]s.
* @param pressedElevation the elevation used when the [FloatingActionButton] is pressed.
* @param focusedElevation the elevation used when the [FloatingActionButton] is focused.
* @param hoveredElevation the elevation used when the [FloatingActionButton] is hovered.
*/
@Composable
fun elevation(
defaultElevation: Dp = FabPrimaryTokens.ContainerElevation,
pressedElevation: Dp = FabPrimaryTokens.PressedContainerElevation,
focusedElevation: Dp = FabPrimaryTokens.FocusContainerElevation,
hoveredElevation: Dp = FabPrimaryTokens.HoverContainerElevation,
): FloatingActionButtonElevation {
return remember(
defaultElevation,
pressedElevation,
focusedElevation,
hoveredElevation,
) {
DefaultFloatingActionButtonElevation(
defaultElevation = defaultElevation,
pressedElevation = pressedElevation,
focusedElevation = focusedElevation,
hoveredElevation = hoveredElevation,
)
}
}
/**
* Use this to create a [FloatingActionButton] with a lowered elevation for less emphasis. Use
* [elevation] to get a normal [FloatingActionButton].
*
* @param defaultElevation the elevation used when the [FloatingActionButton] has no other
* [Interaction]s.
* @param pressedElevation the elevation used when the [FloatingActionButton] is pressed.
* @param focusedElevation the elevation used when the [FloatingActionButton] is focused.
* @param hoveredElevation the elevation used when the [FloatingActionButton] is hovered.
*/
@Composable
fun loweredElevation(
defaultElevation: Dp = FabPrimaryTokens.LoweredContainerElevation,
pressedElevation: Dp = FabPrimaryTokens.LoweredPressedContainerElevation,
focusedElevation: Dp = FabPrimaryTokens.LoweredFocusContainerElevation,
hoveredElevation: Dp = FabPrimaryTokens.LoweredHoverContainerElevation,
): FloatingActionButtonElevation {
return remember(
defaultElevation,
pressedElevation,
focusedElevation,
hoveredElevation,
) {
DefaultFloatingActionButtonElevation(
defaultElevation = defaultElevation,
pressedElevation = pressedElevation,
focusedElevation = focusedElevation,
hoveredElevation = hoveredElevation,
)
}
}
}
/**
* Default [FloatingActionButtonElevation] implementation.
*/
@Stable
private class DefaultFloatingActionButtonElevation(
private val defaultElevation: Dp,
private val pressedElevation: Dp,
private val focusedElevation: Dp,
private val hoveredElevation: Dp,
) : FloatingActionButtonElevation {
@Composable
override fun shadowElevation(interactionSource: InteractionSource): State {
return animateElevation(interactionSource = interactionSource)
}
@Composable
override fun tonalElevation(interactionSource: InteractionSource): State {
return animateElevation(interactionSource = interactionSource)
}
@Composable
private fun animateElevation(interactionSource: InteractionSource): State {
val interactions = remember { mutableStateListOf() }
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect { interaction ->
when (interaction) {
is HoverInteraction.Enter -> {
interactions.add(interaction)
}
is HoverInteraction.Exit -> {
interactions.remove(interaction.enter)
}
is FocusInteraction.Focus -> {
interactions.add(interaction)
}
is FocusInteraction.Unfocus -> {
interactions.remove(interaction.focus)
}
is PressInteraction.Press -> {
interactions.add(interaction)
}
is PressInteraction.Release -> {
interactions.remove(interaction.press)
}
is PressInteraction.Cancel -> {
interactions.remove(interaction.press)
}
}
}
}
val interaction = interactions.lastOrNull()
val target = when (interaction) {
is PressInteraction.Press -> pressedElevation
is HoverInteraction.Enter -> hoveredElevation
is FocusInteraction.Focus -> focusedElevation
else -> defaultElevation
}
val animatable = remember { Animatable(target, Dp.VectorConverter) }
LaunchedEffect(target) {
val lastInteraction = when (animatable.targetValue) {
pressedElevation -> PressInteraction.Press(Offset.Zero)
hoveredElevation -> HoverInteraction.Enter()
focusedElevation -> FocusInteraction.Focus()
else -> null
}
animatable.animateElevation(
from = lastInteraction,
to = interaction,
target = target,
)
}
return animatable.asState()
}
}
private val ExtendedFabStartIconPadding = 16.dp
private val ExtendedFabEndIconPadding = 12.dp
private val ExtendedFabTextPadding = 20.dp
private val ExtendedFabMinimumWidth = 80.dp
private val ExtendedFabCollapseAnimation = fadeOut(
animationSpec = tween(
durationMillis = MotionTokens.Duration100DurationMs.toInt(),
easing = MotionTokens.EasingLinearCubicBezier,
)
) + shrinkHorizontally(
animationSpec = tween(
durationMillis = MotionTokens.Duration500DurationMs.toInt(),
easing = MotionTokens.EasingEmphasizedCubicBezier,
),
shrinkTowards = Alignment.Start,
)
private val ExtendedFabExpandAnimation = fadeIn(
animationSpec = tween(
durationMillis = MotionTokens.Duration200DurationMs.toInt(),
delayMillis = MotionTokens.Duration100DurationMs.toInt(),
easing = MotionTokens.EasingLinearCubicBezier,
),
) + expandHorizontally(
animationSpec = tween(
durationMillis = MotionTokens.Duration500DurationMs.toInt(),
easing = MotionTokens.EasingEmphasizedCubicBezier,
),
expandFrom = Alignment.Start,
)