| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 #import "ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.h" | 5 #import "ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.h" |
| 6 | 6 |
| 7 #import <QuartzCore/CAAnimation.h> | 7 #import <QuartzCore/CAAnimation.h> |
| 8 #import <QuartzCore/CAMediaTimingFunction.h> | 8 #import <QuartzCore/CAMediaTimingFunction.h> |
| 9 | 9 |
| 10 #include "ios/chrome/browser/ui/toolbar/toolbar_button_tints.h" | 10 #include "ios/chrome/browser/ui/toolbar/toolbar_button_tints.h" |
| 11 | 11 |
| 12 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 13 #error "This file requires ARC support." |
| 14 #endif |
| 15 |
| 12 namespace { | 16 namespace { |
| 13 // The number of dots drawn. | 17 // The number of dots drawn. |
| 14 const int kNumberOfDots = 3; | 18 const int kNumberOfDots = 3; |
| 15 // Position of the topmost dot. | 19 // Position of the topmost dot. |
| 16 const CGFloat kDotOffsetX = 22; | 20 const CGFloat kDotOffsetX = 22; |
| 17 const CGFloat kDotOffsetY = 18; | 21 const CGFloat kDotOffsetY = 18; |
| 18 // Vertical space between dots. | 22 // Vertical space between dots. |
| 19 const CGFloat kVerticalSpaceBetweenDots = 6; | 23 const CGFloat kVerticalSpaceBetweenDots = 6; |
| 20 // The duration of the animation, in seconds. | 24 // The duration of the animation, in seconds. |
| 21 const CFTimeInterval kAnimationDuration = 1; | 25 const CFTimeInterval kAnimationDuration = 1; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 41 } // namespace | 45 } // namespace |
| 42 | 46 |
| 43 @interface ToolbarToolsMenuButton ()<CAAnimationDelegate> { | 47 @interface ToolbarToolsMenuButton ()<CAAnimationDelegate> { |
| 44 // The style of the toolbar the button is in. | 48 // The style of the toolbar the button is in. |
| 45 ToolbarControllerStyle style_; | 49 ToolbarControllerStyle style_; |
| 46 // Whether the tools menu is visible. | 50 // Whether the tools menu is visible. |
| 47 BOOL toolsMenuVisible_; | 51 BOOL toolsMenuVisible_; |
| 48 // Whether the reading list contains unseen items. | 52 // Whether the reading list contains unseen items. |
| 49 BOOL readingListContainsUnseenItems_; | 53 BOOL readingListContainsUnseenItems_; |
| 50 // The CALayers containing the drawn dots. | 54 // The CALayers containing the drawn dots. |
| 51 base::scoped_nsobject<CAShapeLayer> pathLayers_[kNumberOfDots]; | 55 NSMutableArray<CAShapeLayer*>* pathLayers_; |
| 52 // Whether the CALayers are being animated. | 56 // Whether the CALayers are being animated. |
| 53 BOOL animationOnGoing_; | 57 BOOL animationOnGoing_; |
| 54 } | 58 } |
| 55 // Updates the tint configuration based on the button's situation, e.g. whether | 59 // Updates the tint configuration based on the button's situation, e.g. whether |
| 56 // the tools menu is visible or not. | 60 // the tools menu is visible or not. |
| 57 - (void)updateTintOfButton; | 61 - (void)updateTintOfButton; |
| 58 // Initializes the pathLayers. | 62 // Initializes the pathLayers. |
| 59 - (void)initializeShapeLayers; | 63 - (void)initializeShapeLayers; |
| 60 // Returns a keyframe-based animation of the property identified by |keyPath|. | 64 // Returns a keyframe-based animation of the property identified by |keyPath|. |
| 61 // The animation immidiately sets the property's value to |initialValue|. | 65 // The animation immidiately sets the property's value to |initialValue|. |
| 62 // After |frameStart| frames, the property's value animates to | 66 // After |frameStart| frames, the property's value animates to |
| 63 // |intermediaryValue|, and then to |finalValue|. | 67 // |intermediaryValue|, and then to |finalValue|. |
| 64 - (CAAnimation*)animationWithInitialValue:(id)initialValue | 68 - (CAAnimation*)animationWithInitialValue:(id)initialValue |
| 65 intermediaryValue:(id)intermediaryValue | 69 intermediaryValue:(id)intermediaryValue |
| 66 finalValue:(id)finalValue | 70 finalValue:(id)finalValue |
| 67 frameStart:(int)frameStart | 71 frameStart:(int)frameStart |
| 68 forKeyPath:(NSString*)keyPath; | 72 forKeyPath:(NSString*)keyPath; |
| 69 // Starts animating the button towards the color |targetColor|. | 73 // Starts animating the button towards the color |targetColor|. |
| 70 - (void)animateToColor:(UIColor*)targetColor; | 74 - (void)animateToColor:(UIColor*)targetColor; |
| 71 @end | 75 @end |
| 72 | 76 |
| 73 @implementation ToolbarToolsMenuButton | 77 @implementation ToolbarToolsMenuButton |
| 74 | 78 |
| 75 - (instancetype)initWithFrame:(CGRect)frame | 79 - (instancetype)initWithFrame:(CGRect)frame |
| 76 style:(ToolbarControllerStyle)style { | 80 style:(ToolbarControllerStyle)style { |
| 77 if (self = [super initWithFrame:frame]) { | 81 if (self = [super initWithFrame:frame]) { |
| 78 style_ = style; | 82 style_ = style; |
| 83 pathLayers_ = [[NSMutableArray alloc] initWithCapacity:kNumberOfDots]; |
| 79 | 84 |
| 80 [self setTintColor:toolbar::NormalButtonTint(style_) | 85 [self setTintColor:toolbar::NormalButtonTint(style_) |
| 81 forState:UIControlStateNormal]; | 86 forState:UIControlStateNormal]; |
| 82 [self setTintColor:toolbar::HighlighButtonTint(style_) | 87 [self setTintColor:toolbar::HighlighButtonTint(style_) |
| 83 forState:UIControlStateHighlighted]; | 88 forState:UIControlStateHighlighted]; |
| 84 } | 89 } |
| 85 return self; | 90 return self; |
| 86 } | 91 } |
| 87 | 92 |
| 88 - (void)setToolsMenuIsVisible:(BOOL)toolsMenuVisible { | 93 - (void)setToolsMenuIsVisible:(BOOL)toolsMenuVisible { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 105 if (toolsMenuVisible_ || readingListContainsUnseenItems_) { | 110 if (toolsMenuVisible_ || readingListContainsUnseenItems_) { |
| 106 [self setTintColor:toolbar::HighlighButtonTint(style_) | 111 [self setTintColor:toolbar::HighlighButtonTint(style_) |
| 107 forState:UIControlStateNormal]; | 112 forState:UIControlStateNormal]; |
| 108 } else { | 113 } else { |
| 109 [self setTintColor:toolbar::NormalButtonTint(style_) | 114 [self setTintColor:toolbar::NormalButtonTint(style_) |
| 110 forState:UIControlStateNormal]; | 115 forState:UIControlStateNormal]; |
| 111 } | 116 } |
| 112 } | 117 } |
| 113 | 118 |
| 114 - (void)initializeShapeLayers { | 119 - (void)initializeShapeLayers { |
| 115 for (int i = 0; i < kNumberOfDots; i++) { | 120 for (NSUInteger i = 0; i < pathLayers_.count; i++) { |
| 116 base::scoped_nsobject<CAShapeLayer>& pathLayer = pathLayers_[i]; | 121 [pathLayers_[i] removeFromSuperlayer]; |
| 117 if (pathLayer) { | 122 } |
| 118 [pathLayer removeFromSuperlayer]; | |
| 119 } | |
| 120 | 123 |
| 124 pathLayers_ = [[NSMutableArray alloc] initWithCapacity:kNumberOfDots]; |
| 125 for (NSUInteger i = 0; i < kNumberOfDots; i++) { |
| 121 const CGFloat x = kDotOffsetX; | 126 const CGFloat x = kDotOffsetX; |
| 122 const CGFloat y = kDotOffsetY + kVerticalSpaceBetweenDots * i; | 127 const CGFloat y = kDotOffsetY + kVerticalSpaceBetweenDots * i; |
| 123 | 128 |
| 124 UIBezierPath* path = [UIBezierPath bezierPath]; | 129 UIBezierPath* path = [UIBezierPath bezierPath]; |
| 125 [path moveToPoint:CGPointMake(x - kMaxWidthOfSegment * 0.5, y)]; | 130 [path moveToPoint:CGPointMake(x - kMaxWidthOfSegment * 0.5, y)]; |
| 126 [path addLineToPoint:CGPointMake(x + kMaxWidthOfSegment * 0.5, y)]; | 131 [path addLineToPoint:CGPointMake(x + kMaxWidthOfSegment * 0.5, y)]; |
| 127 | 132 |
| 128 pathLayer.reset([[CAShapeLayer layer] retain]); | 133 CAShapeLayer* pathLayer = [CAShapeLayer layer]; |
| 129 [pathLayer setFrame:self.bounds]; | 134 [pathLayer setFrame:self.bounds]; |
| 130 [pathLayer setPath:path.CGPath]; | 135 [pathLayer setPath:path.CGPath]; |
| 131 [pathLayer setStrokeColor:[self.tintColor CGColor]]; | 136 [pathLayer setStrokeColor:[self.tintColor CGColor]]; |
| 132 [pathLayer setFillColor:nil]; | 137 [pathLayer setFillColor:nil]; |
| 133 [pathLayer setLineWidth:kLineWidthAtRest]; | 138 [pathLayer setLineWidth:kLineWidthAtRest]; |
| 134 [pathLayer setLineCap:kCALineCapRound]; | 139 [pathLayer setLineCap:kCALineCapRound]; |
| 135 [pathLayer setStrokeStart:kStrokeStartAtRest]; | 140 [pathLayer setStrokeStart:kStrokeStartAtRest]; |
| 136 [pathLayer setStrokeEnd:kStrokeEndAtRest]; | 141 [pathLayer setStrokeEnd:kStrokeEndAtRest]; |
| 137 [self.layer addSublayer:pathLayer.get()]; | 142 [self.layer addSublayer:pathLayer]; |
| 143 [pathLayers_ addObject:pathLayer]; |
| 138 } | 144 } |
| 139 } | 145 } |
| 140 | 146 |
| 141 - (CAAnimation*)animationWithInitialValue:(id)initialValue | 147 - (CAAnimation*)animationWithInitialValue:(id)initialValue |
| 142 intermediaryValue:(id)intermediaryValue | 148 intermediaryValue:(id)intermediaryValue |
| 143 finalValue:(id)finalValue | 149 finalValue:(id)finalValue |
| 144 frameStart:(int)frameStart | 150 frameStart:(int)frameStart |
| 145 forKeyPath:(NSString*)keyPath { | 151 forKeyPath:(NSString*)keyPath { |
| 146 // The property is animated the following way: | 152 // The property is animated the following way: |
| 147 // | 153 // |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 DCHECK_LE([number floatValue], 1); | 203 DCHECK_LE([number floatValue], 1); |
| 198 } | 204 } |
| 199 #endif | 205 #endif |
| 200 | 206 |
| 201 return animation; | 207 return animation; |
| 202 } | 208 } |
| 203 | 209 |
| 204 - (void)animateToColor:(UIColor*)targetColor { | 210 - (void)animateToColor:(UIColor*)targetColor { |
| 205 animationOnGoing_ = YES; | 211 animationOnGoing_ = YES; |
| 206 | 212 |
| 213 DCHECK(pathLayers_.count == kNumberOfDots); |
| 207 // Add four animations for each stroke. | 214 // Add four animations for each stroke. |
| 208 for (int i = 0; i < kNumberOfDots; i++) { | 215 for (int i = 0; i < kNumberOfDots; i++) { |
| 209 base::scoped_nsobject<CAShapeLayer>& pathLayer = pathLayers_[i]; | 216 CAShapeLayer* pathLayer = pathLayers_[i]; |
| 210 DCHECK(pathLayer.get()); | |
| 211 const int frameStart = | 217 const int frameStart = |
| 212 (kNumberOfDots - i) * kFramesBetweenAnimationOfEachDot; | 218 (kNumberOfDots - i) * kFramesBetweenAnimationOfEachDot; |
| 213 | 219 |
| 214 // Start of the stroke animation. | 220 // Start of the stroke animation. |
| 215 CAAnimation* strokeStartAnimation = | 221 CAAnimation* strokeStartAnimation = |
| 216 [self animationWithInitialValue:@(kStrokeStartAtRest) | 222 [self animationWithInitialValue:@(kStrokeStartAtRest) |
| 217 intermediaryValue:@(kStrokeStartAtApogee) | 223 intermediaryValue:@(kStrokeStartAtApogee) |
| 218 finalValue:@(kStrokeStartAtRest) | 224 finalValue:@(kStrokeStartAtRest) |
| 219 frameStart:frameStart | 225 frameStart:frameStart |
| 220 forKeyPath:@"strokeStart"]; | 226 forKeyPath:@"strokeStart"]; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 #pragma mark - CAAnimationDelegate | 286 #pragma mark - CAAnimationDelegate |
| 281 | 287 |
| 282 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag { | 288 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag { |
| 283 animationOnGoing_ = NO; | 289 animationOnGoing_ = NO; |
| 284 // Recreate the CAShapeLayers in case the tint code changed while the | 290 // Recreate the CAShapeLayers in case the tint code changed while the |
| 285 // animation was going on. | 291 // animation was going on. |
| 286 [self initializeShapeLayers]; | 292 [self initializeShapeLayers]; |
| 287 } | 293 } |
| 288 | 294 |
| 289 @end | 295 @end |
| OLD | NEW |