| /* |
| * 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.core.Animatable |
| import androidx.compose.animation.core.AnimationSpec |
| import androidx.compose.animation.core.CubicBezierEasing |
| import androidx.compose.animation.core.Easing |
| import androidx.compose.animation.core.FastOutSlowInEasing |
| import androidx.compose.animation.core.TweenSpec |
| import androidx.compose.foundation.interaction.DragInteraction |
| import androidx.compose.foundation.interaction.FocusInteraction |
| import androidx.compose.foundation.interaction.HoverInteraction |
| import androidx.compose.foundation.interaction.Interaction |
| import androidx.compose.foundation.interaction.PressInteraction |
| import androidx.compose.ui.unit.Dp |
| |
| /** |
| * Animates the [Dp] value of [this] between [from] and [to] [Interaction]s, to [target]. The |
| * [AnimationSpec] used depends on the values for [from] and [to], see |
| * [ElevationDefaults.incomingAnimationSpecForInteraction] and |
| * [ElevationDefaults.outgoingAnimationSpecForInteraction] for more details. |
| * |
| * @param target the [Dp] target elevation for this component, corresponding to the elevation |
| * desired for the [to] state. |
| * @param from the previous [Interaction] that was used to calculate elevation. `null` if there |
| * was no previous [Interaction], such as when the component is in its default state. |
| * @param to the [Interaction] that this component is moving to, such as [PressInteraction.Press] |
| * when this component is being pressed. `null` if this component is moving back to its default |
| * state. |
| */ |
| internal suspend fun Animatable<Dp, *>.animateElevation( |
| target: Dp, |
| from: Interaction? = null, |
| to: Interaction? = null |
| ) { |
| val spec = when { |
| // Moving to a new state |
| to != null -> ElevationDefaults.incomingAnimationSpecForInteraction(to) |
| // Moving to default, from a previous state |
| from != null -> ElevationDefaults.outgoingAnimationSpecForInteraction(from) |
| // Loading the initial state, or moving back to the baseline state from a disabled / |
| // unknown state, so just snap to the final value. |
| else -> null |
| } |
| if (spec != null) animateTo(target, spec) else snapTo(target) |
| } |
| |
| /** |
| * Contains default [AnimationSpec]s used for animating elevation between different [Interaction]s. |
| * |
| * Typically you should use [animateElevation] instead, which uses these [AnimationSpec]s |
| * internally. [animateElevation] in turn is used by the defaults for cards and buttons. |
| * |
| * @see animateElevation |
| */ |
| private object ElevationDefaults { |
| /** |
| * Returns the [AnimationSpec]s used when animating elevation to [interaction], either from a |
| * previous [Interaction], or from the default state. If [interaction] is unknown, then |
| * returns `null`. |
| * |
| * @param interaction the [Interaction] that is being animated to |
| */ |
| fun incomingAnimationSpecForInteraction(interaction: Interaction): AnimationSpec<Dp>? { |
| return when (interaction) { |
| is PressInteraction.Press -> DefaultIncomingSpec |
| is DragInteraction.Start -> DefaultIncomingSpec |
| is HoverInteraction.Enter -> DefaultIncomingSpec |
| is FocusInteraction.Focus -> DefaultIncomingSpec |
| else -> null |
| } |
| } |
| |
| /** |
| * Returns the [AnimationSpec]s used when animating elevation away from [interaction], to the |
| * default state. If [interaction] is unknown, then returns `null`. |
| * |
| * @param interaction the [Interaction] that is being animated away from |
| */ |
| fun outgoingAnimationSpecForInteraction(interaction: Interaction): AnimationSpec<Dp>? { |
| return when (interaction) { |
| is PressInteraction.Press -> DefaultOutgoingSpec |
| is DragInteraction.Start -> DefaultOutgoingSpec |
| is HoverInteraction.Enter -> HoveredOutgoingSpec |
| is FocusInteraction.Focus -> DefaultOutgoingSpec |
| else -> null |
| } |
| } |
| } |
| |
| private val OutgoingSpecEasing: Easing = CubicBezierEasing(0.40f, 0.00f, 0.60f, 1.00f) |
| |
| private val DefaultIncomingSpec = TweenSpec<Dp>( |
| durationMillis = 120, |
| easing = FastOutSlowInEasing |
| ) |
| |
| private val DefaultOutgoingSpec = TweenSpec<Dp>( |
| durationMillis = 150, |
| easing = OutgoingSpecEasing |
| ) |
| |
| private val HoveredOutgoingSpec = TweenSpec<Dp>( |
| durationMillis = 120, |
| easing = OutgoingSpecEasing |
| ) |