Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: ui/views/animation/ink_drop_animation_controller_impl.cc

Issue 1280953003: Enhance the material design ripple API so the ripple's state can be controlled by it's owning View. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed pkasting@'s comments from patch set 11 Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/animation/ink_drop_animation_controller.h" 5 #include "ui/views/animation/ink_drop_animation_controller_impl.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "ui/base/ui_base_switches.h" 8 #include "ui/base/ui_base_switches.h"
9 #include "ui/compositor/layer.h" 9 #include "ui/compositor/layer.h"
10 #include "ui/compositor/layer_animation_observer.h" 10 #include "ui/compositor/layer_animation_observer.h"
11 #include "ui/compositor/layer_animation_sequence.h" 11 #include "ui/compositor/layer_animation_sequence.h"
12 #include "ui/compositor/paint_recorder.h" 12 #include "ui/compositor/paint_recorder.h"
13 #include "ui/compositor/scoped_layer_animation_settings.h" 13 #include "ui/compositor/scoped_layer_animation_settings.h"
14 #include "ui/events/event.h" 14 #include "ui/events/event.h"
15 #include "ui/gfx/canvas.h" 15 #include "ui/gfx/canvas.h"
16 #include "ui/gfx/geometry/size.h"
17 #include "ui/views/animation/ink_drop_delegate.h"
18 #include "ui/views/animation/ink_drop_host.h"
16 #include "ui/views/view.h" 19 #include "ui/views/view.h"
17 20
18 namespace { 21 namespace {
19 22
20 // Animation constants 23 // Animation constants
21 const float kMinimumScale = 0.1f; 24 const float kMinimumScale = 0.1f;
22 const float kMinimumScaleCenteringOffset = 0.5f - kMinimumScale / 2.0f; 25 const float kMinimumScaleCenteringOffset = 0.5f - kMinimumScale / 2.0f;
23 26
24 const int kHideAnimationDurationFastMs = 100; 27 const int kHideAnimationDurationFastMs = 100;
25 const int kHideAnimationDurationSlowMs = 1000; 28 const int kHideAnimationDurationSlowMs = 1000;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 ui::Layer* background_layer_; 109 ui::Layer* background_layer_;
107 110
108 // If true the hide animation will immediately be scheduled upon completion of 111 // If true the hide animation will immediately be scheduled upon completion of
109 // the observed animation. 112 // the observed animation.
110 bool hide_; 113 bool hide_;
111 114
112 DISALLOW_COPY_AND_ASSIGN(AppearAnimationObserver); 115 DISALLOW_COPY_AND_ASSIGN(AppearAnimationObserver);
113 }; 116 };
114 117
115 AppearAnimationObserver::AppearAnimationObserver(ui::Layer* layer, bool hide) 118 AppearAnimationObserver::AppearAnimationObserver(ui::Layer* layer, bool hide)
116 : layer_(layer), background_layer_(nullptr), hide_(hide) { 119 : layer_(layer), background_layer_(nullptr), hide_(hide) {}
117 }
118 120
119 AppearAnimationObserver::~AppearAnimationObserver() { 121 AppearAnimationObserver::~AppearAnimationObserver() {
120 StopObserving(); 122 StopObserving();
121 } 123 }
122 124
123 bool AppearAnimationObserver::IsAnimationActive() { 125 bool AppearAnimationObserver::IsAnimationActive() {
124 // Initial animation ongoing 126 // Initial animation ongoing
125 if (!attached_sequences().empty()) 127 if (!attached_sequences().empty())
126 return true; 128 return true;
127 // Maintain the animation until told to hide. 129 // Maintain the animation until told to hide.
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 StartHideAnimation(); 177 StartHideAnimation();
176 } 178 }
177 179
178 bool AppearAnimationObserver::RequiresNotificationWhenAnimatorDestroyed() 180 bool AppearAnimationObserver::RequiresNotificationWhenAnimatorDestroyed()
179 const { 181 const {
180 // Ensures that OnImplicitAnimationsCompleted is called even if the observed 182 // Ensures that OnImplicitAnimationsCompleted is called even if the observed
181 // animation is deleted. Allows for setting the proper state on |layer_|. 183 // animation is deleted. Allows for setting the proper state on |layer_|.
182 return true; 184 return true;
183 } 185 }
184 186
185 // Renders the visual feedback. Will render a circle if |circle_| is true, 187 InkDropAnimationControllerImpl::InkDropAnimationControllerImpl(
186 // otherwise renders a rounded rectangle. 188 InkDropHost* ink_drop_host)
187 class InkDropDelegate : public ui::LayerDelegate { 189 : InkDropAnimationController(ink_drop_host),
188 public: 190 ink_drop_host_(ink_drop_host),
189 InkDropDelegate(ui::Layer* layer, SkColor color); 191 layer_tree_(new ui::Layer()),
190 ~InkDropDelegate() override; 192 ink_drop_layer_(new ui::Layer()),
193 ink_drop_delegate_(new InkDropDelegate(ink_drop_layer_,
194 kInkDropColor,
195 kCircleRadius,
196 kRoundedRectCorners)),
197 appear_animation_observer_(nullptr),
198 long_press_layer_(new ui::Layer()),
199 long_press_delegate_(new InkDropDelegate(long_press_layer_,
200 kLongPressColor,
201 kCircleRadius,
202 kRoundedRectCorners)),
203 long_press_animation_observer_(nullptr),
204 ink_drop_bounds_(0, 0, 0, 0) {
205 SetupAnimationLayer(long_press_layer_, long_press_delegate_.get());
206 SetupAnimationLayer(ink_drop_layer_, ink_drop_delegate_.get());
191 207
192 // Sets the visual style of the feedback. 208 layer_tree_.root()->Add(ink_drop_layer_);
193 void set_should_render_circle(bool should_render_circle) { 209 layer_tree_.root()->Add(long_press_layer_);
sadrul 2015/08/17 14:33:06 This does not pass ownership of |ink_drop_layer_|,
bruthig 2015/08/17 17:43:39 The LayerTreeOwner will delete all the roots desce
194 should_render_circle_ = should_render_circle;
195 }
196 210
197 // ui::LayerDelegate: 211 ink_drop_host_->AddInkDropLayer(layer_tree_.root());
198 void OnPaintLayer(const ui::PaintContext& context) override;
199 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
200 void OnDeviceScaleFactorChanged(float device_scale_factor) override;
201 base::Closure PrepareForLayerBoundsChange() override;
202
203 private:
204 // The ui::Layer being rendered to.
205 ui::Layer* layer_;
206
207 // The color to paint.
208 SkColor color_;
209
210 // When true renders a circle, otherwise renders a rounded rectangle.
211 bool should_render_circle_;
212
213 DISALLOW_COPY_AND_ASSIGN(InkDropDelegate);
214 };
215
216 InkDropDelegate::InkDropDelegate(ui::Layer* layer, SkColor color)
217 : layer_(layer), color_(color), should_render_circle_(true) {
218 } 212 }
219 213
220 InkDropDelegate::~InkDropDelegate() { 214 InkDropAnimationControllerImpl::~InkDropAnimationControllerImpl() {
215 // TODO(bruthig): Currently this virtual function is going to be called during
216 // ToolbarButton's destructor, is that ok?? This should hopefully change and
217 // be called when the Ink Drop becomes hidden.
sadrul 2015/08/17 14:33:06 Update the comment (e.g. 'Change this to be called
bruthig 2015/08/17 17:43:39 Done.
218 ink_drop_host_->RemoveInkDropLayer(layer_tree_.root());
221 } 219 }
222 220
223 void InkDropDelegate::OnPaintLayer(const ui::PaintContext& context) { 221 void InkDropAnimationControllerImpl::AnimateToState(InkDropState state) {
224 SkPaint paint; 222 // TODO(bruthig): Do not transition if we are already in |state| and restrict
225 paint.setColor(color_); 223 // any state transition that don't make sense or wouldn't look visually
226 paint.setFlags(SkPaint::kAntiAlias_Flag); 224 // appealing.
227 paint.setStyle(SkPaint::kFill_Style); 225 switch (state) {
228 226 case InkDropState::HIDDEN:
229 gfx::Rect bounds = layer_->bounds(); 227 AnimateHide();
230 228 break;
231 ui::PaintRecorder recorder(context, layer_->size()); 229 case InkDropState::ACTION_PENDING:
232 gfx::Canvas* canvas = recorder.canvas(); 230 AnimateTapDown();
233 if (should_render_circle_) { 231 break;
234 gfx::Point midpoint(bounds.width() * 0.5f, bounds.height() * 0.5f); 232 case InkDropState::QUICK_ACTION:
235 canvas->DrawCircle(midpoint, kCircleRadius, paint); 233 AnimateTapDown();
236 } else { 234 AnimateHide();
237 canvas->DrawRoundRect(bounds, kRoundedRectCorners, paint); 235 break;
236 case InkDropState::SLOW_ACTION:
237 AnimateLongPress();
238 break;
239 case InkDropState::ACTIVATED:
240 AnimateLongPress();
241 break;
238 } 242 }
239 } 243 }
240 244
241 void InkDropDelegate::OnDelegatedFrameDamage( 245 void InkDropAnimationControllerImpl::SetInkDropSize(const gfx::Size& size) {
242 const gfx::Rect& damage_rect_in_dip) { 246 SetInkDropBounds(gfx::Rect(ink_drop_bounds_.x(), ink_drop_bounds_.y(),
247 size.width(), size.height()));
sadrul 2015/08/17 14:33:06 gfx::Rect(ink_drop_bounds_.origin(), size())
bruthig 2015/08/17 17:43:39 Done.
243 } 248 }
244 249
245 void InkDropDelegate::OnDeviceScaleFactorChanged(float device_scale_factor) { 250 gfx::Rect InkDropAnimationControllerImpl::GetInkDropBounds() const {
251 return ink_drop_bounds_;
246 } 252 }
247 253
248 base::Closure InkDropDelegate::PrepareForLayerBoundsChange() { 254 void InkDropAnimationControllerImpl::SetInkDropBounds(const gfx::Rect& bounds) {
249 return base::Closure(); 255 ink_drop_bounds_ = bounds;
256 SetLayerBounds(ink_drop_layer_);
257 SetLayerBounds(long_press_layer_);
250 } 258 }
251 259
252 InkDropAnimationController::InkDropAnimationController(views::View* view) 260 void InkDropAnimationControllerImpl::AnimateTapDown() {
253 : ink_drop_layer_(new ui::Layer()),
254 ink_drop_delegate_(
255 new InkDropDelegate(ink_drop_layer_.get(), kInkDropColor)),
256 appear_animation_observer_(nullptr),
257 long_press_layer_(new ui::Layer()),
258 long_press_delegate_(
259 new InkDropDelegate(long_press_layer_.get(), kLongPressColor)),
260 long_press_animation_observer_(nullptr),
261 view_(view) {
262 view_->SetPaintToLayer(true);
263 view_->AddPreTargetHandler(this);
264 ui::Layer* layer = view_->layer();
265 layer->SetMasksToBounds(!UseCircularFeedback());
266 SetupAnimationLayer(layer, long_press_layer_.get(),
267 long_press_delegate_.get());
268 SetupAnimationLayer(layer, ink_drop_layer_.get(), ink_drop_delegate_.get());
269 ink_drop_delegate_->set_should_render_circle(UseCircularFeedback());
270 }
271
272 InkDropAnimationController::~InkDropAnimationController() {
273 view_->RemovePreTargetHandler(this);
274 }
275
276 void InkDropAnimationController::AnimateTapDown() {
277 if ((appear_animation_observer_ && 261 if ((appear_animation_observer_ &&
278 appear_animation_observer_->IsAnimationActive()) || 262 appear_animation_observer_->IsAnimationActive()) ||
279 (long_press_animation_observer_ && 263 (long_press_animation_observer_ &&
280 long_press_animation_observer_->IsAnimationActive())) { 264 long_press_animation_observer_->IsAnimationActive())) {
281 // Only one animation at a time. Subsequent tap downs are ignored until the 265 // Only one animation at a time. Subsequent tap downs are ignored until the
282 // current animation completes. 266 // current animation completes.
283 return; 267 return;
284 } 268 }
285 appear_animation_observer_.reset( 269 appear_animation_observer_.reset(
286 new AppearAnimationObserver(ink_drop_layer_.get(), false)); 270 new AppearAnimationObserver(ink_drop_layer_, false));
287 AnimateShow(ink_drop_layer_.get(), appear_animation_observer_.get(), 271 AnimateShow(ink_drop_layer_, appear_animation_observer_.get(),
288 UseCircularFeedback(),
289 base::TimeDelta::FromMilliseconds( 272 base::TimeDelta::FromMilliseconds(
290 (UseFastAnimations() ? kShowInkDropAnimationDurationFastMs 273 (UseFastAnimations() ? kShowInkDropAnimationDurationFastMs
291 : kShowInkDropAnimationDurationSlowMs))); 274 : kShowInkDropAnimationDurationSlowMs)));
292 } 275 }
293 276
294 void InkDropAnimationController::AnimateHide() { 277 void InkDropAnimationControllerImpl::AnimateHide() {
295 if (appear_animation_observer_) 278 if (appear_animation_observer_ &&
279 appear_animation_observer_->IsAnimationActive()) {
296 appear_animation_observer_->HideNowIfDoneOrOnceCompleted(); 280 appear_animation_observer_->HideNowIfDoneOrOnceCompleted();
281 } else if (long_press_animation_observer_) {
282 long_press_animation_observer_->HideNowIfDoneOrOnceCompleted();
283 }
297 } 284 }
298 285
299 void InkDropAnimationController::AnimateLongPress() { 286 void InkDropAnimationControllerImpl::AnimateLongPress() {
300 // Only one animation at a time. Subsequent long presses are ignored until the 287 // Only one animation at a time. Subsequent long presses are ignored until the
301 // current animation completes. 288 // current animation completes.
302 if (long_press_animation_observer_ && 289 if (long_press_animation_observer_ &&
303 long_press_animation_observer_->IsAnimationActive()) { 290 long_press_animation_observer_->IsAnimationActive()) {
304 return; 291 return;
305 } 292 }
306 appear_animation_observer_.reset(); 293 appear_animation_observer_.reset();
307 long_press_animation_observer_.reset( 294 long_press_animation_observer_.reset(
308 new AppearAnimationObserver(long_press_layer_.get(), true)); 295 new AppearAnimationObserver(long_press_layer_, false));
309 long_press_animation_observer_->SetBackgroundToHide(ink_drop_layer_.get()); 296 long_press_animation_observer_->SetBackgroundToHide(ink_drop_layer_);
310 AnimateShow(long_press_layer_.get(), long_press_animation_observer_.get(), 297 AnimateShow(long_press_layer_, long_press_animation_observer_.get(),
311 true,
312 base::TimeDelta::FromMilliseconds( 298 base::TimeDelta::FromMilliseconds(
313 UseFastAnimations() ? kShowLongPressAnimationDurationFastMs 299 UseFastAnimations() ? kShowLongPressAnimationDurationFastMs
314 : kShowLongPressAnimationDurationSlowMs)); 300 : kShowLongPressAnimationDurationSlowMs));
315 } 301 }
316 302
317 void InkDropAnimationController::AnimateShow(ui::Layer* layer, 303 void InkDropAnimationControllerImpl::AnimateShow(
318 AppearAnimationObserver* observer, 304 ui::Layer* layer,
319 bool circle, 305 AppearAnimationObserver* observer,
320 base::TimeDelta duration) { 306 base::TimeDelta duration) {
321 SetLayerBounds(layer, circle, view_->width(), view_->height());
322 layer->SetVisible(true); 307 layer->SetVisible(true);
323 layer->SetOpacity(1.0f); 308 layer->SetOpacity(1.0f);
324 309
325 float start_x = layer->bounds().width() * kMinimumScaleCenteringOffset; 310 float start_x = ink_drop_bounds_.x() +
326 float start_y = layer->bounds().height() * kMinimumScaleCenteringOffset; 311 layer->bounds().width() * kMinimumScaleCenteringOffset;
312 float start_y = ink_drop_bounds_.y() +
313 layer->bounds().height() * kMinimumScaleCenteringOffset;
327 314
328 gfx::Transform initial_transform; 315 gfx::Transform initial_transform;
329 initial_transform.Translate(start_x, start_y); 316 initial_transform.Translate(start_x, start_y);
330 initial_transform.Scale(kMinimumScale, kMinimumScale); 317 initial_transform.Scale(kMinimumScale, kMinimumScale);
331 layer->SetTransform(initial_transform); 318 layer->SetTransform(initial_transform);
332 319
333 ui::LayerAnimator* animator = layer->GetAnimator(); 320 ui::LayerAnimator* animator = layer->GetAnimator();
334 ui::ScopedLayerAnimationSettings animation(animator); 321 ui::ScopedLayerAnimationSettings animation(animator);
335 animation.SetPreemptionStrategy( 322 animation.SetPreemptionStrategy(
336 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 323 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
337 324
338 gfx::Transform identity_transform; 325 gfx::Transform target_transform;
326 target_transform.Translate(ink_drop_bounds_.x(), ink_drop_bounds_.y());
339 ui::LayerAnimationElement* element = 327 ui::LayerAnimationElement* element =
340 ui::LayerAnimationElement::CreateTransformElement(identity_transform, 328 ui::LayerAnimationElement::CreateTransformElement(target_transform,
341 duration); 329 duration);
342 ui::LayerAnimationSequence* sequence = 330 ui::LayerAnimationSequence* sequence =
343 new ui::LayerAnimationSequence(element); 331 new ui::LayerAnimationSequence(element);
344 sequence->AddObserver(observer); 332 sequence->AddObserver(observer);
345 animator->StartAnimation(sequence); 333 animator->StartAnimation(sequence);
346 } 334 }
347 335
348 void InkDropAnimationController::SetLayerBounds(ui::Layer* layer, 336 void InkDropAnimationControllerImpl::SetLayerBounds(ui::Layer* layer) {
349 bool circle, 337 bool circle = UseCircularFeedback();
350 int width, 338 gfx::Size size = ink_drop_bounds_.size();
351 int height) { 339 float circle_width = circle ? 2.0f * kCircleRadius : size.width();
352 float circle_width = circle ? 2.0f * kCircleRadius : width; 340 float circle_height = circle ? 2.0f * kCircleRadius : size.height();
353 float circle_height = circle ? 2.0f * kCircleRadius : height; 341 float circle_x = circle ? (size.width() - circle_width) * 0.5f : 0;
354 float circle_x = circle ? (width - circle_width) * 0.5f : 0; 342 float circle_y = circle ? (size.height() - circle_height) * 0.5f : 0;
355 float circle_y = circle ? (height - circle_height) * 0.5f : 0;
356 layer->SetBounds(gfx::Rect(circle_x, circle_y, circle_width, circle_height)); 343 layer->SetBounds(gfx::Rect(circle_x, circle_y, circle_width, circle_height));
357 } 344 }
358 345
359 void InkDropAnimationController::SetupAnimationLayer( 346 void InkDropAnimationControllerImpl::SetupAnimationLayer(
360 ui::Layer* parent,
361 ui::Layer* layer, 347 ui::Layer* layer,
362 InkDropDelegate* delegate) { 348 InkDropDelegate* delegate) {
363 layer->SetFillsBoundsOpaquely(false); 349 layer->SetFillsBoundsOpaquely(false);
364 layer->set_delegate(delegate); 350 layer->set_delegate(delegate);
365 layer->SetVisible(false); 351 layer->SetVisible(false);
366 layer->SetBounds(gfx::Rect()); 352 layer->SetBounds(gfx::Rect());
367 parent->Add(layer); 353 delegate->set_should_render_circle(UseCircularFeedback());
368 parent->StackAtBottom(layer);
369 }
370
371 void InkDropAnimationController::OnGestureEvent(ui::GestureEvent* event) {
372 if (event->target() != view_)
373 return;
374
375 switch (event->type()) {
376 case ui::ET_GESTURE_TAP_DOWN:
377 AnimateTapDown();
378 break;
379 case ui::ET_GESTURE_LONG_PRESS:
380 AnimateLongPress();
381 break;
382 case ui::ET_GESTURE_END:
383 case ui::ET_GESTURE_TAP_CANCEL:
384 case ui::ET_GESTURE_TAP:
385 AnimateHide();
386 break;
387 default:
388 break;
389 }
390 } 354 }
391 355
392 } // namespace views 356 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698