| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef UI_VIEWS_ANIMATION_BOUNDS_ANIMATOR_H_ |
| #define UI_VIEWS_ANIMATION_BOUNDS_ANIMATOR_H_ |
| |
| #include <map> |
| #include <memory> |
| |
| #include "base/compiler_specific.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/observer_list.h" |
| #include "ui/gfx/animation/animation_container.h" |
| #include "ui/gfx/animation/animation_container_observer.h" |
| #include "ui/gfx/animation/tween.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/views/animation/animation_delegate_views.h" |
| #include "ui/views/views_export.h" |
| |
| namespace gfx { |
| class SlideAnimation; |
| } |
| |
| namespace views { |
| |
| class BoundsAnimatorObserver; |
| class View; |
| |
| // Bounds animator is responsible for animating the bounds of a view from the |
| // the views current location and size to a target position and size. To use |
| // BoundsAnimator invoke AnimateViewTo for the set of views you want to |
| // animate. |
| // |
| // BoundsAnimator internally creates an animation for each view. If you need |
| // a specific animation invoke SetAnimationForView after invoking AnimateViewTo. |
| // You can attach an AnimationDelegate to the individual animation for a view |
| // by way of SetAnimationDelegate. Additionally you can attach an observer to |
| // the BoundsAnimator that is notified when all animations are complete. |
| // |
| // There is an option to apply transforms on the view instead of repainting and |
| // relayouting each animation tick. This should be used if the size of the view |
| // is not changing. It can be considered, but may have funny looking visuals for |
| // other cases, depending on the content. If layers are not present, they are |
| // created and destroyed as necessary. |
| class VIEWS_EXPORT BoundsAnimator : public AnimationDelegateViews { |
| public: |
| explicit BoundsAnimator(View* view, bool use_transforms = false); |
| ~BoundsAnimator() override; |
| |
| // Starts animating |view| from its current bounds to |target|. If there is |
| // already an animation running for the view it's stopped and a new one |
| // started. If an AnimationDelegate has been set for |view| it is removed |
| // (after being notified that the animation was canceled). |
| void AnimateViewTo( |
| View* view, |
| const gfx::Rect& target, |
| std::unique_ptr<gfx::AnimationDelegate> delegate = nullptr); |
| |
| // Similar to |AnimateViewTo|, but does not reset the animation, only the |
| // target bounds. If |view| is not being animated this is the same as |
| // invoking |AnimateViewTo|. |
| void SetTargetBounds(View* view, const gfx::Rect& target); |
| |
| // Returns the target bounds for the specified view. If |view| is not |
| // animating its current bounds is returned. |
| gfx::Rect GetTargetBounds(const View* view) const; |
| |
| // Returns the animation for the specified view. BoundsAnimator owns the |
| // returned Animation. |
| const gfx::SlideAnimation* GetAnimationForView(View* view); |
| |
| // Stops animating the specified view. |
| void StopAnimatingView(View* view); |
| |
| // Sets the delegate for the animation for the specified view. |
| void SetAnimationDelegate(View* view, |
| std::unique_ptr<gfx::AnimationDelegate> delegate); |
| |
| // Returns true if BoundsAnimator is animating the bounds of |view|. |
| bool IsAnimating(View* view) const; |
| |
| // Returns true if BoundsAnimator is animating any view. |
| bool IsAnimating() const; |
| |
| // Cancels all animations, leaving the views at their current location and |
| // size. Any views marked for deletion are deleted. |
| void Cancel(); |
| |
| // Overrides default animation duration. |
| void SetAnimationDuration(base::TimeDelta duration); |
| |
| // Gets the currently used animation duration. |
| base::TimeDelta GetAnimationDuration() const { return animation_duration_; } |
| |
| // Sets the tween type for new animations. Default is EASE_OUT. |
| void set_tween_type(gfx::Tween::Type type) { tween_type_ = type; } |
| |
| void AddObserver(BoundsAnimatorObserver* observer); |
| void RemoveObserver(BoundsAnimatorObserver* observer); |
| |
| gfx::AnimationContainer* container() { return container_.get(); } |
| |
| protected: |
| // Creates the animation to use for animating views. |
| virtual std::unique_ptr<gfx::SlideAnimation> CreateAnimation(); |
| |
| private: |
| // Tracks data about the view being animated. |
| struct Data { |
| Data(); |
| Data(Data&&); |
| Data& operator=(Data&&); |
| ~Data(); |
| |
| // The initial bounds. |
| gfx::Rect start_bounds; |
| |
| // Target bounds. |
| gfx::Rect target_bounds; |
| |
| // The animation. |
| std::unique_ptr<gfx::SlideAnimation> animation; |
| |
| // Delegate for the animation, may be nullptr. |
| std::unique_ptr<gfx::AnimationDelegate> delegate; |
| |
| // Will only exist if |use_transforms_| is true. |
| absl::optional<gfx::Transform> target_transform; |
| }; |
| |
| // Used by AnimationEndedOrCanceled. |
| enum class AnimationEndType { kEnded, kCanceled }; |
| |
| using ViewToDataMap = std::map<const View*, Data>; |
| |
| using AnimationToViewMap = std::map<const gfx::Animation*, View*>; |
| |
| // Removes references to |view| and its animation. Returns the data for the |
| // caller to handle cleanup. |
| Data RemoveFromMaps(View* view); |
| |
| // Does the necessary cleanup for |data|. If |send_cancel| is true and a |
| // delegate has been installed on |data| AnimationCanceled is invoked on it. |
| void CleanupData(bool send_cancel, Data* data); |
| |
| // Used when changing the animation for a view. This resets the maps for |
| // the animation used by view and returns the current animation. Ownership |
| // of the returned animation passes to the caller. |
| std::unique_ptr<gfx::Animation> ResetAnimationForView(View* view); |
| |
| // Invoked from AnimationEnded and AnimationCanceled. |
| void AnimationEndedOrCanceled(const gfx::Animation* animation, |
| AnimationEndType type); |
| |
| // AnimationDelegateViews overrides. |
| void AnimationProgressed(const gfx::Animation* animation) override; |
| void AnimationEnded(const gfx::Animation* animation) override; |
| void AnimationCanceled(const gfx::Animation* animation) override; |
| void AnimationContainerProgressed( |
| gfx::AnimationContainer* container) override; |
| void AnimationContainerEmpty(gfx::AnimationContainer* container) override; |
| void OnChildViewRemoved(views::View* observed_view, |
| views::View* child) override; |
| base::TimeDelta GetAnimationDurationForReporting() const override; |
| |
| // Parent of all views being animated. |
| View* parent_; |
| |
| // A more performant version of the bounds animations which updates the |
| // transform of the views and therefore skips repainting and relayouting until |
| // the end of the animation. Note that this may not look as good as the |
| // regular version, depending on the content and the source and destination |
| // bounds. In the case the provided source bounds is empty, we cannot derive a |
| // transform so that particular view will still use a bounds animation, even |
| // with this flag on. |
| const bool use_transforms_; |
| |
| base::ObserverList<BoundsAnimatorObserver>::Unchecked observers_; |
| |
| // All animations we create up with the same container. |
| scoped_refptr<gfx::AnimationContainer> container_; |
| |
| // Maps from view being animated to info about the view. |
| ViewToDataMap data_; |
| |
| // Maps from animation to view. |
| AnimationToViewMap animation_to_view_; |
| |
| // As the animations we create update (AnimationProgressed is invoked) this |
| // is updated. When all the animations have completed for a given tick of |
| // the timer (AnimationContainerProgressed is invoked) the parent_ is asked |
| // to repaint these bounds. |
| gfx::Rect repaint_bounds_; |
| |
| base::TimeDelta animation_duration_ = base::TimeDelta::FromMilliseconds(200); |
| |
| gfx::Tween::Type tween_type_ = gfx::Tween::EASE_OUT; |
| |
| DISALLOW_COPY_AND_ASSIGN(BoundsAnimator); |
| }; |
| |
| } // namespace views |
| |
| #endif // UI_VIEWS_ANIMATION_BOUNDS_ANIMATOR_H_ |