[go: nahoru, domu]

blob: b104e209a5eddc0f8afc391af64512e5a9e5153e [file] [log] [blame]
Anthony Robledo8db013f2021-10-18 11:35:53 -04001/*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package androidx.compose.material3
18
19import androidx.compose.animation.core.Animatable
20import androidx.compose.animation.core.AnimationSpec
21import androidx.compose.animation.core.CubicBezierEasing
22import androidx.compose.animation.core.Easing
23import androidx.compose.animation.core.FastOutSlowInEasing
24import androidx.compose.animation.core.TweenSpec
25import androidx.compose.foundation.interaction.DragInteraction
26import androidx.compose.foundation.interaction.FocusInteraction
27import androidx.compose.foundation.interaction.HoverInteraction
28import androidx.compose.foundation.interaction.Interaction
29import androidx.compose.foundation.interaction.PressInteraction
30import androidx.compose.ui.unit.Dp
31
32/**
33 * Animates the [Dp] value of [this] between [from] and [to] [Interaction]s, to [target]. The
34 * [AnimationSpec] used depends on the values for [from] and [to], see
35 * [ElevationDefaults.incomingAnimationSpecForInteraction] and
36 * [ElevationDefaults.outgoingAnimationSpecForInteraction] for more details.
37 *
38 * @param target the [Dp] target elevation for this component, corresponding to the elevation
39 * desired for the [to] state.
40 * @param from the previous [Interaction] that was used to calculate elevation. `null` if there
41 * was no previous [Interaction], such as when the component is in its default state.
42 * @param to the [Interaction] that this component is moving to, such as [PressInteraction.Press]
43 * when this component is being pressed. `null` if this component is moving back to its default
44 * state.
45 */
46internal suspend fun Animatable<Dp, *>.animateElevation(
47 target: Dp,
48 from: Interaction? = null,
49 to: Interaction? = null
50) {
51 val spec = when {
52 // Moving to a new state
53 to != null -> ElevationDefaults.incomingAnimationSpecForInteraction(to)
54 // Moving to default, from a previous state
55 from != null -> ElevationDefaults.outgoingAnimationSpecForInteraction(from)
56 // Loading the initial state, or moving back to the baseline state from a disabled /
57 // unknown state, so just snap to the final value.
58 else -> null
59 }
60 if (spec != null) animateTo(target, spec) else snapTo(target)
61}
62
63/**
64 * Contains default [AnimationSpec]s used for animating elevation between different [Interaction]s.
65 *
66 * Typically you should use [animateElevation] instead, which uses these [AnimationSpec]s
67 * internally. [animateElevation] in turn is used by the defaults for cards and buttons.
68 *
69 * @see animateElevation
70 */
71private object ElevationDefaults {
72 /**
73 * Returns the [AnimationSpec]s used when animating elevation to [interaction], either from a
74 * previous [Interaction], or from the default state. If [interaction] is unknown, then
75 * returns `null`.
76 *
77 * @param interaction the [Interaction] that is being animated to
78 */
79 fun incomingAnimationSpecForInteraction(interaction: Interaction): AnimationSpec<Dp>? {
80 return when (interaction) {
81 is PressInteraction.Press -> DefaultIncomingSpec
82 is DragInteraction.Start -> DefaultIncomingSpec
83 is HoverInteraction.Enter -> DefaultIncomingSpec
84 is FocusInteraction.Focus -> DefaultIncomingSpec
85 else -> null
86 }
87 }
88
89 /**
90 * Returns the [AnimationSpec]s used when animating elevation away from [interaction], to the
91 * default state. If [interaction] is unknown, then returns `null`.
92 *
93 * @param interaction the [Interaction] that is being animated away from
94 */
95 fun outgoingAnimationSpecForInteraction(interaction: Interaction): AnimationSpec<Dp>? {
96 return when (interaction) {
97 is PressInteraction.Press -> DefaultOutgoingSpec
98 is DragInteraction.Start -> DefaultOutgoingSpec
99 is HoverInteraction.Enter -> HoveredOutgoingSpec
100 is FocusInteraction.Focus -> DefaultOutgoingSpec
101 else -> null
102 }
103 }
104}
105
106private val OutgoingSpecEasing: Easing = CubicBezierEasing(0.40f, 0.00f, 0.60f, 1.00f)
107
108private val DefaultIncomingSpec = TweenSpec<Dp>(
109 durationMillis = 120,
110 easing = FastOutSlowInEasing
111)
112
113private val DefaultOutgoingSpec = TweenSpec<Dp>(
114 durationMillis = 150,
115 easing = OutgoingSpecEasing
116)
117
118private val HoveredOutgoingSpec = TweenSpec<Dp>(
119 durationMillis = 120,
120 easing = OutgoingSpecEasing
121)