Skip to content

Commit

Permalink
Upstream iOS UI utilities.
Browse files Browse the repository at this point in the history
TBR=thakis

Review URL: https://codereview.chromium.org/802633007

Cr-Commit-Position: refs/heads/master@{#311284}
  • Loading branch information
droger authored and Commit bot committed Jan 13, 2015
1 parent b960eff commit 72f741a
Show file tree
Hide file tree
Showing 16 changed files with 1,811 additions and 0 deletions.
1 change: 1 addition & 0 deletions ios/chrome/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ include_rules = [
"+ios/public/provider/chrome",
"+ios/web/public",
"+net",
"+third_party/ocmock",
"+ui",

# Only parts of skia are compiled on iOS, so we explicitly list the
Expand Down
42 changes: 42 additions & 0 deletions ios/chrome/browser/ui/animation_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2014 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 IOS_CHROME_BROWSER_UI_ANIMATION_UTIL_H_
#define IOS_CHROME_BROWSER_UI_ANIMATION_UTIL_H_

#import <UIKit/UIKit.h>

// Animations returned by these utility methods use kCAFillModeBoth and aren't
// automatically removed from the layer when finished. Remove the animations
// by calling |RemoveAnimationsFromLayers| in CATransaction completion blocks.
// This is done so the effects of animations that finish earlier persist until
// all animations in the transaction are finished.

// Returns an animation that will animate |layer| from |beginFrame| to
// |endFrame|.
CAAnimation* FrameAnimationMake(CALayer* layer,
CGRect beginFrame,
CGRect endFrame);

// Returns an animation that will animate the "opacity" property of a layer from
// |beginOpacity| to |endOpacity|.
CAAnimation* OpacityAnimationMake(CGFloat beginOpacity, CGFloat endOpacity);

// Returns an animation group containing the animations in |animations| that has
// the shortest duration necessary for all the animations to finish.
CAAnimation* AnimationGroupMake(NSArray* animations);

// Returns an animation that performs |animation| after |delay|.
CAAnimation* DelayedAnimationMake(CAAnimation* animation, CFTimeInterval delay);

// If |animation| is a CAAnimationGroup, searches its animations for a
// CABasicAnimation for |keyPath|. If |animation| is a CABasicAnimation, it
// will check its keyPath against |keyPath|.
CABasicAnimation* FindAnimationForKeyPath(NSString* keyPath,
CAAnimation* animation);

// Removes the animation for |key| from each CALayer in |layers|.
void RemoveAnimationForKeyFromLayers(NSString* key, NSArray* layers);

#endif // IOS_CHROME_BROWSER_UI_ANIMATION_UTIL_H_
94 changes: 94 additions & 0 deletions ios/chrome/browser/ui/animation_util.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright 2014 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.

#include "ios/chrome/browser/ui/animation_util.h"

#include <algorithm>
#include <cmath>

#include "ios/chrome/browser/ui/reversed_animation.h"

CAAnimation* FrameAnimationMake(CALayer* layer,
CGRect beginFrame,
CGRect endFrame) {
CGRect beginBounds = {CGPointZero, beginFrame.size};
CGRect endBounds = {CGPointZero, endFrame.size};
CABasicAnimation* boundsAnimation =
[CABasicAnimation animationWithKeyPath:@"bounds"];
boundsAnimation.fromValue = [NSValue valueWithCGRect:beginBounds];
boundsAnimation.toValue = [NSValue valueWithCGRect:endBounds];
boundsAnimation.removedOnCompletion = NO;
boundsAnimation.fillMode = kCAFillModeBoth;
CGPoint beginPosition = CGPointMake(
beginFrame.origin.x + layer.anchorPoint.x * beginBounds.size.width,
beginFrame.origin.y + layer.anchorPoint.y * beginBounds.size.height);
CGPoint endPosition = CGPointMake(
endFrame.origin.x + layer.anchorPoint.x * endBounds.size.width,
endFrame.origin.y + layer.anchorPoint.y * endBounds.size.height);
CABasicAnimation* positionAnimation =
[CABasicAnimation animationWithKeyPath:@"position"];
positionAnimation.fromValue = [NSValue valueWithCGPoint:beginPosition];
positionAnimation.toValue = [NSValue valueWithCGPoint:endPosition];
positionAnimation.removedOnCompletion = NO;
positionAnimation.fillMode = kCAFillModeBoth;
return AnimationGroupMake(@[ boundsAnimation, positionAnimation ]);
}

CAAnimation* OpacityAnimationMake(CGFloat beginOpacity, CGFloat endOpacity) {
CABasicAnimation* opacityAnimation =
[CABasicAnimation animationWithKeyPath:@"opacity"];
opacityAnimation.fromValue = @(beginOpacity);
opacityAnimation.toValue = @(endOpacity);
opacityAnimation.fillMode = kCAFillModeBoth;
opacityAnimation.removedOnCompletion = NO;
return opacityAnimation;
}

CAAnimation* AnimationGroupMake(NSArray* animations) {
CAAnimationGroup* animationGroup = [CAAnimationGroup animation];
animationGroup.animations = animations;
CFTimeInterval duration = 0.0;
for (CAAnimation* animation in animations)
duration = std::max(duration, animation.beginTime + animation.duration);
animationGroup.duration = duration;
animationGroup.fillMode = kCAFillModeBoth;
animationGroup.removedOnCompletion = NO;
return animationGroup;
}

CAAnimation* DelayedAnimationMake(CAAnimation* animation,
CFTimeInterval delay) {
CAAnimation* delayedAnimation = [[animation copy] autorelease];
if (delayedAnimation) {
delayedAnimation.beginTime = delay;
delayedAnimation = AnimationGroupMake(@[ delayedAnimation ]);
}
return delayedAnimation;
}

CABasicAnimation* FindAnimationForKeyPath(NSString* keyPath,
CAAnimation* animation) {
__block CABasicAnimation* animationForKeyPath = nil;
if ([animation isKindOfClass:[CABasicAnimation class]]) {
CABasicAnimation* basicAnimation =
static_cast<CABasicAnimation*>(animation);
if ([basicAnimation.keyPath isEqualToString:keyPath])
animationForKeyPath = basicAnimation;
} else if ([animation isKindOfClass:[CAAnimationGroup class]]) {
CAAnimationGroup* animationGroup =
static_cast<CAAnimationGroup*>(animation);
[animationGroup.animations
enumerateObjectsUsingBlock:^(CAAnimation* subAnimation, NSUInteger idx,
BOOL* stop) {
animationForKeyPath = FindAnimationForKeyPath(keyPath, subAnimation);
*stop = animationForKeyPath != nil;
}];
}
return animationForKeyPath;
}

void RemoveAnimationForKeyFromLayers(NSString* key, NSArray* layers) {
for (CALayer* layer in layers)
[layer removeAnimationForKey:key];
}
18 changes: 18 additions & 0 deletions ios/chrome/browser/ui/reversed_animation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2014 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 IOS_CHROME_BROWSER_UI_REVERSED_ANIMATION_H_
#define IOS_CHROME_BROWSER_UI_REVERSED_ANIMATION_H_

#import <UIKit/UIKit.h>

// Returns an animation that reverses |animation| when added to |layer|.
CAAnimation* CAAnimationMakeReverse(CAAnimation* animation, CALayer* layer);

// Removes the animation for |key| from each CALayer in |layers|, creates
// reversed versions using |CAAnimationMakeReverse|, then adds the reversed
// animation back to the layers under the same key.
void ReverseAnimationsForKeyForLayers(NSString* key, NSArray* layers);

#endif // IOS_CHROME_BROWSER_UI_REVERSED_ANIMATION_H_
Loading

0 comments on commit 72f741a

Please sign in to comment.