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|. |
(...skipping 12 matching lines...) Expand all Loading... |
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; |
79 | 83 |
80 [self setTintColor:toolbar::NormalButtonTint(style_) | 84 [self setTintColor:toolbar::NormalButtonTint(style_) |
81 forState:UIControlStateNormal]; | 85 forState:UIControlStateNormal]; |
82 [self setTintColor:toolbar::HighlighButtonTint(style_) | 86 [self setTintColor:toolbar::HighlighButtonTint(style_) |
83 forState:UIControlStateHighlighted]; | 87 forState:UIControlStateHighlighted]; |
| 88 pathLayers_ = [[NSMutableArray alloc] initWithCapacity:kNumberOfDots]; |
84 } | 89 } |
85 return self; | 90 return self; |
86 } | 91 } |
87 | 92 |
88 - (void)setToolsMenuIsVisible:(BOOL)toolsMenuVisible { | 93 - (void)setToolsMenuIsVisible:(BOOL)toolsMenuVisible { |
89 toolsMenuVisible_ = toolsMenuVisible; | 94 toolsMenuVisible_ = toolsMenuVisible; |
90 [self updateTintOfButton]; | 95 [self updateTintOfButton]; |
91 } | 96 } |
92 | 97 |
93 - (void)setReadingListContainsUnseenItems:(BOOL)readingListContainsUnseenItems { | 98 - (void)setReadingListContainsUnseenItems:(BOOL)readingListContainsUnseenItems { |
(...skipping 12 matching lines...) Expand all Loading... |
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 (int i = 0; i < kNumberOfDots; i++) { |
116 base::scoped_nsobject<CAShapeLayer>& pathLayer = pathLayers_[i]; | 121 CAShapeLayer* pathLayer = pathLayers_[i]; |
117 if (pathLayer) { | 122 if (pathLayer) { |
118 [pathLayer removeFromSuperlayer]; | 123 [pathLayer removeFromSuperlayer]; |
119 } | 124 } |
120 | 125 |
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 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_[i] = 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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 |
207 // Add four animations for each stroke. | 213 // Add four animations for each stroke. |
208 for (int i = 0; i < kNumberOfDots; i++) { | 214 for (int i = 0; i < kNumberOfDots; i++) { |
209 base::scoped_nsobject<CAShapeLayer>& pathLayer = pathLayers_[i]; | 215 CAShapeLayer* pathLayer = pathLayers_[i]; |
210 DCHECK(pathLayer.get()); | |
211 const int frameStart = | 216 const int frameStart = |
212 (kNumberOfDots - i) * kFramesBetweenAnimationOfEachDot; | 217 (kNumberOfDots - i) * kFramesBetweenAnimationOfEachDot; |
213 | 218 |
214 // Start of the stroke animation. | 219 // Start of the stroke animation. |
215 CAAnimation* strokeStartAnimation = | 220 CAAnimation* strokeStartAnimation = |
216 [self animationWithInitialValue:@(kStrokeStartAtRest) | 221 [self animationWithInitialValue:@(kStrokeStartAtRest) |
217 intermediaryValue:@(kStrokeStartAtApogee) | 222 intermediaryValue:@(kStrokeStartAtApogee) |
218 finalValue:@(kStrokeStartAtRest) | 223 finalValue:@(kStrokeStartAtRest) |
219 frameStart:frameStart | 224 frameStart:frameStart |
220 forKeyPath:@"strokeStart"]; | 225 forKeyPath:@"strokeStart"]; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 #pragma mark - CAAnimationDelegate | 285 #pragma mark - CAAnimationDelegate |
281 | 286 |
282 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag { | 287 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag { |
283 animationOnGoing_ = NO; | 288 animationOnGoing_ = NO; |
284 // Recreate the CAShapeLayers in case the tint code changed while the | 289 // Recreate the CAShapeLayers in case the tint code changed while the |
285 // animation was going on. | 290 // animation was going on. |
286 [self initializeShapeLayers]; | 291 [self initializeShapeLayers]; |
287 } | 292 } |
288 | 293 |
289 @end | 294 @end |
OLD | NEW |