blob: 02cfffd27e8588b08e76be85148ed276547f07d9 [file] [log] [blame] [view]
Wei Lifc6f3e02021-09-08 23:52:331
2## Layer Animation Builder
3
4
5### Purpose
6
7Integrating animation and kinetic UI movements can be difficult to set up. Where to start and what to override (if anything) isn’t very clear. Making animations more declarative in nature rather than manually gluing all the lower-level animation subsystems together will simplify their use.
8
9This system provides a programmatic model that is similar to how the UX team creates animations. This ensures more fidelity between the intent of the UX designer and the resulting code. The visual similarities between the presentation used by the UX and the actual code constructing those sequences will make maintenance and updates easier and quicker.
10
11
12### Example
13
14In order to better demonstrate how this system makes constructing animations easier an example should make this more clear.
15
16The following code will create a repeating cross-fading animation shown below.
17
18![animation_step1](images/animation_builder1.png) ![animation_step2](images/animation_builder1.png) ![animation_step3](images/animation_builder1.png)
19
James Cookaec05042021-10-28 17:53:0820You can see this animation by running `views_examples` on Windows or Linux:
21
22``` shell
23$ autoninja -C out\Default views_examples
24$ out\Default\views_examples --enable-examples="Fade Animation"
25```
Wei Lifc6f3e02021-09-08 23:52:3326
27Traditionally this would be how the above animation would be created.
28
29
30``` cpp
31 auto primary_sequence = std::make_unique<ui::LayerAnimationSequence>();
32 auto secondary_sequence = std::make_unique<ui::LayerAnimationSequence>();
33 primary_sequence->set_is_repeating(true);
34 secondary_sequence->set_is_repeating(true);
35
36 primary_sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
Peter Kastinge5a38ed2021-10-02 03:06:3537 ui::LayerAnimationElement::OPACITY, base::Seconds(2)));
Wei Lifc6f3e02021-09-08 23:52:3338 primary_sequence->AddElement(ui::LayerAnimationElement::CreateOpacityElement(
Peter Kastinge5a38ed2021-10-02 03:06:3539 0.0f, base::Seconds(1)));
Wei Lifc6f3e02021-09-08 23:52:3340 primary_sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
Peter Kastinge5a38ed2021-10-02 03:06:3541 ui::LayerAnimationElement::OPACITY, base::Seconds(2)));
Wei Lifc6f3e02021-09-08 23:52:3342 primary_sequence->AddElement(ui::LayerAnimationElement::CreateOpacityElement(
Peter Kastinge5a38ed2021-10-02 03:06:3543 1.0f, base::Seconds(1)));
Wei Lifc6f3e02021-09-08 23:52:3344
45 secondary_sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
Peter Kastinge5a38ed2021-10-02 03:06:3546 ui::LayerAnimationElement::OPACITY, base::Seconds(2)));
Wei Lifc6f3e02021-09-08 23:52:3347 secondary_sequence->AddElement(
48 ui::LayerAnimationElement::CreateOpacityElement(
Peter Kastinge5a38ed2021-10-02 03:06:3549 1.0f, base::Seconds(1)));
Wei Lifc6f3e02021-09-08 23:52:3350 secondary_sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
Peter Kastinge5a38ed2021-10-02 03:06:3551 ui::LayerAnimationElement::OPACITY, base::Seconds(2)));
Wei Lifc6f3e02021-09-08 23:52:3352 secondary_sequence->AddElement(
53 ui::LayerAnimationElement::CreateOpacityElement(
Peter Kastinge5a38ed2021-10-02 03:06:3554 0.0f, base::Seconds(1)));
Wei Lifc6f3e02021-09-08 23:52:3355
56 primary_view_->layer()->GetAnimator()->StartAnimation(
57 primary_sequence.release());
58 secondary_view_->layer()->GetAnimator()->StartAnimation(
59 secondary_sequence.release());
60```
61
62
63Using the new builder system described in this document, the above code could be done much simpler.
64
65
66``` cpp
67 AnimationBuilder()
68 .Repeatedly()
Peter Kastinge5a38ed2021-10-02 03:06:3569 .Offset(base::Seconds(2))
70 .SetDuration(base::Seconds(1))
Wei Lifc6f3e02021-09-08 23:52:3371 .SetOpacity(primary_view_, 0.0f)
72 .SetOpacity(secondary_view_, 1.0f)
Peter Kastinge5a38ed2021-10-02 03:06:3573 .Offset(base::Seconds(2))
74 .SetDuration(base::Seconds(1))
Wei Lifc6f3e02021-09-08 23:52:3375 .SetOpacity(primary_view_, 1.0f)
76 .SetOpacity(secondary_view_, 0.0f);
77```
78
79
80The AnimationBuilder will handle proper insertion of pause elements into the timeline, so no specific need to insert them. It will also handle coordination of the animations across multiple [LayerOwner](https://source.chromium.org/chromium/chromium/src/+/main:ui/compositor/layer_owner.h;l=19)s or across specific [Layers](https://source.chromium.org/chromium/chromium/src/+/main:ui/compositor/layer.h;drc=af5bb21d9ee6585e4111fbc9089d1f5c7edde034;l=69).
81
82It should be obvious that the above code is both shorter and more immediately clear what the intent of the code is doing along with how the animations interact across the two views.
83
84
85### API Reference
86
Elaine Chien46fb5092021-09-15 21:55:0387Currently AnimationBuilder operates only on a LayerOwner or directly on a Layer. Since views::View is also a LayerOwner, it will also operate directly on Views. To animate a View, the View must first paint to it’s layer by calling View::SetPaintToLayer.
Wei Lifc6f3e02021-09-08 23:52:3388
Elaine Chien46fb5092021-09-15 21:55:0389The AnimationBuilder is a scoped object that starts the animations after the AnimationBuilder goes out of scope. This can be done as a single statement (as shown above) or across multiple statements with local temps.
Wei Lifc6f3e02021-09-08 23:52:3390
91NOTE: It is generally _not_ recommended to hold onto an AnimationBuilder instance beyond the current scope or store it in instance variables. This could lead to UAFs or other undesirable behaviors. Simply construct the animation at the point at which it is needed.
92
93To use AnimationBuilder include the following header:
94
95
96``` cpp
97#include "ui/views/animation/animation_builder.h"
98```
99
Elaine Chien46fb5092021-09-15 21:55:03100The AnimationBuilder consists of the main object along with an inner AnimationSequenceBlock.
Wei Lifc6f3e02021-09-08 23:52:33101
Elaine Chien46fb5092021-09-15 21:55:03102An AnimationSequenceBlock is a single unit of a larger animation sequence, which has a start time, duration, and zero or more (target, property) animations.
103* There may be multiple properties animating on a single target, and/or multiple targets animating, but the same property on the same target may only be animated at most once per block. Animations can be added by calling SetXXX().
104* Calling At(), Offset(), or Then() creates a new block. All animations in the same AnimationSequenceBlock will run in parallel. Create multiple AnimationSequenceBlocks to run animations in sequence.
Wei Lifc6f3e02021-09-08 23:52:33105
Elaine Chien46fb5092021-09-15 21:55:03106Calls on AnimationBuilder affect the whole animations and calls on AnimationSequenceBlock affect only that particular block.
107
Elaine Chien9ee333172022-07-28 13:04:31108#### Setting callbacks
109When setting callbacks for the animations note that the AnimationBuilder’s observer that calls these callbacks may outlive the callback's parameters.
Wei Lifc6f3e02021-09-08 23:52:33110
Elaine Chieneb7088a2022-08-02 00:15:54111The OnEnded callback runs when all animations created on the AnimationBuilder have finished. The OnAborted callback runs when any one animation created on the AnimationBuilder has been aborted. Therefore, these callbacks and every object the callback accesses needs to outlive all the Layers/LayerOwners being animated on since the Layers ultimately own the objects that run the animation. Otherwise developers may need to use weak pointers or force animations to be cancelled in the object’s destructor to prevent accessing destroyed objects. Note that aborted notifications can be sent during the destruction process. Therefore subclasses that own the Layers may actually be destroyed before the OnAborted callback is run.
Elaine Chien9ee333172022-07-28 13:04:31112
113#### API
Wei Lifc6f3e02021-09-08 23:52:33114``` cpp
115class VIEWS_EXPORT AnimationBuilder {
116 public:
117 AnimationBuilder();
118 ~AnimationBuilder();
119
120 // Options for the whole animation
Elaine Chien46fb5092021-09-15 21:55:03121
Wei Lifc6f3e02021-09-08 23:52:33122 AnimationBuilder& SetPreemptionStrategy(
123 ui::LayerAnimator::PreemptionStrategy preemption_strategy);
Elaine Chien46fb5092021-09-15 21:55:03124 // Called when the animation starts.
125 AnimationBuilder& OnStarted(base::OnceClosure callback);
126 // Called when the animation ends. Not called if animation is aborted.
127 AnimationBuilder& OnEnded(base::OnceClosure callback);
128 // Called when a sequence repetition ends and will repeat. Not called if
129 // sequence is aborted.
130 AnimationBuilder& OnWillRepeat(base::RepeatingClosure callback);
131 // Called if animation is aborted for any reason. Should never do anything
132 // that may cause another animation to be started.
133 AnimationBuilder& OnAborted(base::OnceClosure callback);
134 // Called when the animation is scheduled.
135 AnimationBuilder& OnScheduled(base::OnceClosure callback);
Wei Lifc6f3e02021-09-08 23:52:33136
137 // Creates a new sequence (that optionally repeats).
138 AnimationSequenceBlock Once();
139 AnimationSequenceBlock Repeatedly();
140
141 // Returns a handle that can be destroyed later to abort all running
142 // animations.
143 // Caveat: ALL properties will be aborted, including those not initiated
144 // by the builder.
145 std::unique_ptr<AnimationAbortHandle> GetAbortHandle();
146};
147
Elaine Chien46fb5092021-09-15 21:55:03148
Wei Lifc6f3e02021-09-08 23:52:33149class VIEWS_EXPORT AnimationSequenceBlock {
150 public:
151 AnimationSequenceBlock(base::PassKey<AnimationBuilder> builder_key,
152 AnimationBuilder* owner,
153 base::TimeDelta start);
154 AnimationSequenceBlock(AnimationSequenceBlock&& other);
155 AnimationSequenceBlock& operator=(AnimationSequenceBlock&& other);
156 ~AnimationSequenceBlock();
157
158 // Sets the duration of this block. The duration may be set at most once and
159 // will be zero if unspecified.
160 AnimationSequenceBlock& SetDuration(base::TimeDelta duration);
161
162 // Adds animation elements to this block. Each (target, property) pair may be
163 // added at most once.
Elaine Chien46fb5092021-09-15 21:55:03164 // These property setter methods can also take in a ui::Layer as the target.
Wei Lifc6f3e02021-09-08 23:52:33165 AnimationSequenceBlock& SetBounds(
166 ui::LayerOwner* target,
167 const gfx::Rect& bounds,
168 gfx::Tween::Type tween_type = gfx::Tween::LINEAR);
169 AnimationSequenceBlock& SetBrightness(
Wei Lifc6f3e02021-09-08 23:52:33170 ui::LayerOwner* target,
171 float brightness,
172 gfx::Tween::Type tween_type = gfx::Tween::LINEAR);
173 AnimationSequenceBlock& SetClipRect(
Wei Lifc6f3e02021-09-08 23:52:33174 ui::LayerOwner* target,
175 const gfx::Rect& clip_rect,
176 gfx::Tween::Type tween_type = gfx::Tween::LINEAR);
177 AnimationSequenceBlock& SetColor(
Wei Lifc6f3e02021-09-08 23:52:33178 ui::LayerOwner* target,
179 SkColor color,
180 gfx::Tween::Type tween_type = gfx::Tween::LINEAR);
181 AnimationSequenceBlock& SetGrayscale(
Wei Lifc6f3e02021-09-08 23:52:33182 ui::LayerOwner* target,
183 float grayscale,
184 gfx::Tween::Type tween_type = gfx::Tween::LINEAR);
185 AnimationSequenceBlock& SetOpacity(
Wei Lifc6f3e02021-09-08 23:52:33186 ui::LayerOwner* target,
187 float opacity,
188 gfx::Tween::Type tween_type = gfx::Tween::LINEAR);
189 AnimationSequenceBlock& SetTransform(
Wei Lifc6f3e02021-09-08 23:52:33190 ui::LayerOwner* target,
191 gfx::Transform transform,
192 gfx::Tween::Type tween_type = gfx::Tween::LINEAR);
193 AnimationSequenceBlock& SetRoundedCorners(
Wei Lifc6f3e02021-09-08 23:52:33194 ui::LayerOwner* target,
195 const gfx::RoundedCornersF& rounded_corners,
196 gfx::Tween::Type tween_type = gfx::Tween::LINEAR);
197 AnimationSequenceBlock& SetVisibility(
Wei Lifc6f3e02021-09-08 23:52:33198 ui::LayerOwner* target,
199 bool visible,
200 gfx::Tween::Type tween_type = gfx::Tween::LINEAR);
201
202 // Creates a new block.
203 AnimationSequenceBlock At(base::TimeDelta since_sequence_start);
204 AnimationSequenceBlock Offset(base::TimeDelta since_last_block_start);
205 AnimationSequenceBlock Then();
Wei Lifc6f3e02021-09-08 23:52:33206};
207```
208