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

Side by Side Diff: ios/chrome/browser/ui/popup_menu/popup_menu_controller.mm

Issue 2589803002: Upstream Chrome on iOS source code [6/11]. (Closed)
Patch Set: Created 4 years 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
(Empty)
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/ui/popup_menu/popup_menu_controller.h"
6
7 #import "base/ios/weak_nsobject.h"
8 #include "base/logging.h"
9 #include "base/mac/bundle_locations.h"
10 #include "base/mac/objc_property_releaser.h"
11 #import "ios/chrome/browser/ui/animation_util.h"
12 #import "ios/chrome/browser/ui/popup_menu/popup_menu_view.h"
13 #include "ios/chrome/browser/ui/rtl_geometry.h"
14 #import "ios/chrome/browser/ui/uikit_ui_util.h"
15 #import "ios/chrome/common/material_timing.h"
16 #include "ios/chrome/grit/ios_strings.h"
17 #include "ui/base/l10n/l10n_util.h"
18
19 using ios::material::TimingFunction;
20
21 namespace {
22 // Inset for the shadows of the contained views.
23 static const CGFloat kPopupMenuVerticalInset = 11.0;
24 // Duration for the Popup Menu Fade In animation
25 static const CGFloat kFadeInAnimationDuration = 0.2;
26 // Value to pass in for backgroundButtonTag to not set a tag value for
27 // |backgroundButton_|.
28 static const NSInteger kBackgroundButtonNoTag = -1;
29 // Default width of the popup container.
30 static const CGFloat kPopupContainerWidth = 236.0;
31 // Default height of the popup container.
32 static const CGFloat kPopupContainerHeight = 280.0;
33 static const CGFloat kPopoverScaleFactor = 0.03;
34
35 static void SetAnchorPoint(CGPoint anchorPoint, UIView* view) {
36 CGPoint oldOrigin = view.frame.origin;
37 view.layer.anchorPoint = anchorPoint;
38 CGPoint newOrigin = view.frame.origin;
39
40 CGPoint transition;
41 transition.x = newOrigin.x - oldOrigin.x;
42 transition.y = newOrigin.y - oldOrigin.y;
43
44 view.center =
45 CGPointMake(view.center.x - transition.x, view.center.y - transition.y);
46 }
47
48 static CGPoint AnimateInIntermediaryPoint(CGPoint source, CGPoint destination) {
49 CGPoint midPoint = CGPointZero;
50 midPoint.x = destination.x;
51 midPoint.y = source.y - 0.8 * fabs(destination.y - source.y);
52 return midPoint;
53 }
54
55 } // anonymous namespace
56
57 @interface PopupMenuController ()<PopupMenuViewDelegate> {
58 base::mac::ObjCPropertyReleaser propertyReleaser_PopupMenuController_;
59 CGPoint sourceAnimationPoint_;
60 }
61 @end
62
63 @implementation PopupMenuController
64
65 @synthesize containerView = containerView_;
66 @synthesize backgroundButton = backgroundButton_;
67 @synthesize popupContainer = popupContainer_;
68 @synthesize delegate = delegate_;
69
70 - (id)initWithParentView:(UIView*)parent {
71 return [self initWithParentView:parent
72 backgroundButtonParent:nil
73 backgroundButtonColor:nil
74 backgroundButtonAlpha:1.0
75 backgroundButtonTag:kBackgroundButtonNoTag
76 backgroundButtonSelector:nil];
77 }
78
79 - (id)initWithParentView:(UIView*)parent
80 backgroundButtonParent:(UIView*)backgroundButtonParent
81 backgroundButtonColor:(UIColor*)backgroundButtonColor
82 backgroundButtonAlpha:(CGFloat)backgroundButtonAlpha
83 backgroundButtonTag:(NSInteger)backgroundButtonTag
84 backgroundButtonSelector:(SEL)backgroundButtonSelector {
85 DCHECK(parent);
86 self = [super init];
87 if (self) {
88 propertyReleaser_PopupMenuController_.Init(self,
89 [PopupMenuController class]);
90
91 popupContainer_ = [[PopupMenuView alloc]
92 initWithFrame:CGRectMake(0, 0, kPopupContainerWidth,
93 kPopupContainerHeight)];
94
95 containerView_ = [[UIView alloc] initWithFrame:[parent bounds]];
96 containerView_.backgroundColor = [UIColor clearColor];
97 [containerView_ setAccessibilityViewIsModal:YES];
98 [popupContainer_ setDelegate:self];
99 // All views are added to the |containerView_| that in turn is added to the
100 // parent view. The Container View is needed to have a simple alpha
101 // transition when the menu is displayed or hidden.
102 [containerView_ addSubview:popupContainer_];
103 [parent addSubview:containerView_];
104
105 // Initialize backgroundButton_.
106 UIView* buttonParent =
107 backgroundButtonParent == nil ? containerView_ : backgroundButtonParent;
108 backgroundButton_ = [[UIButton alloc] initWithFrame:[buttonParent bounds]];
109 [buttonParent addSubview:backgroundButton_];
110 if (buttonParent == containerView_)
111 [buttonParent sendSubviewToBack:backgroundButton_];
112
113 backgroundButton_.autoresizingMask =
114 UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth |
115 UIViewAutoresizingFlexibleBottomMargin |
116 UIViewAutoresizingFlexibleLeadingMargin();
117 backgroundButton_.alpha = backgroundButtonAlpha;
118 if (backgroundButtonTag != kBackgroundButtonNoTag)
119 backgroundButton_.tag = backgroundButtonTag;
120 if (backgroundButtonColor != nil) {
121 backgroundButton_.backgroundColor = backgroundButtonColor;
122 }
123 if (backgroundButtonSelector != nil) {
124 [backgroundButton_ addTarget:nil
125 action:backgroundButtonSelector
126 forControlEvents:UIControlEventTouchDown];
127 } else {
128 [backgroundButton_ addTarget:self
129 action:@selector(tappedBehindPopup:)
130 forControlEvents:UIControlEventTouchDown];
131 }
132 [backgroundButton_ setAccessibilityLabel:l10n_util::GetNSString(
133 IDS_IOS_TOOLBAR_CLOSE_MENU)];
134 }
135 return self;
136 }
137
138 - (void)setOptimalSize:(CGSize)optimalSize atOrigin:(CGPoint)origin {
139 CGRect popupFrame = [popupContainer_ bounds];
140 popupFrame.size.width = optimalSize.width;
141 popupFrame.size.height = 2 * kPopupMenuVerticalInset + optimalSize.height;
142
143 // If the origin is on the right half of the screen, treat origin as the top-
144 // right coordinate instead of top-left.
145 CGFloat xOffset = origin.x > [containerView_ bounds].size.width / 2
146 ? origin.x - popupFrame.size.width
147 : origin.x;
148 [popupContainer_ setFrame:CGRectOffset(popupFrame, xOffset, origin.y)];
149 }
150
151 - (void)fadeInPopupFromSource:(CGPoint)source
152 toDestination:(CGPoint)destination {
153 [self animateInFromPoint:source toPoint:destination];
154 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,
155 containerView_);
156 }
157
158 - (void)dismissAnimatedWithCompletion:(void (^)(void))completion {
159 [self animateOutToPoint:sourceAnimationPoint_ completion:completion];
160 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,
161 nil);
162 }
163
164 // Animate the view on screen (Fade in).
165 - (void)fadeInPopup:(void (^)(BOOL finished))completionBlock {
166 [UIView animateWithDuration:kFadeInAnimationDuration
167 delay:0.0
168 options:UIViewAnimationOptionAllowUserInteraction
169 animations:^{
170 [containerView_ setAlpha:1.0];
171 }
172 completion:completionBlock];
173 }
174
175 - (void)dealloc {
176 [popupContainer_ removeFromSuperview];
177 [backgroundButton_ removeFromSuperview];
178 [containerView_ removeFromSuperview];
179 [super dealloc];
180 }
181
182 - (void)tappedBehindPopup:(id)sender {
183 [self dismissPopupMenu];
184 }
185
186 - (void)animateInFromPoint:(CGPoint)source toPoint:(CGPoint)destination {
187 sourceAnimationPoint_ = source;
188
189 // Set anchor to top right for top right destinations.
190 NSUInteger anchorX =
191 destination.x > [containerView_ bounds].size.width / 2 ? 1 : 0;
192 SetAnchorPoint(CGPointMake(anchorX, 0), popupContainer_);
193
194 CGPoint midPoint = AnimateInIntermediaryPoint(source, destination);
195
196 CATransform3D scaleTransform =
197 CATransform3DMakeScale(kPopoverScaleFactor, kPopoverScaleFactor, 1);
198
199 NSValue* destinationScaleValue =
200 [NSValue valueWithCATransform3D:CATransform3DIdentity];
201
202 CABasicAnimation* scaleAnimation =
203 [CABasicAnimation animationWithKeyPath:@"transform"];
204 CAMediaTimingFunction* easeOut = TimingFunction(ios::material::CurveEaseOut);
205 [scaleAnimation setFromValue:[NSValue valueWithCATransform3D:scaleTransform]];
206 [scaleAnimation setToValue:destinationScaleValue];
207 [scaleAnimation setTimingFunction:easeOut];
208 [scaleAnimation setDuration:ios::material::kDuration1];
209
210 CAKeyframeAnimation* positionAnimation =
211 [CAKeyframeAnimation animationWithKeyPath:@"position"];
212 [positionAnimation setValues:@[
213 [NSValue valueWithCGPoint:source], [NSValue valueWithCGPoint:source],
214 [NSValue valueWithCGPoint:midPoint], [NSValue valueWithCGPoint:destination]
215 ]];
216 [positionAnimation setTimingFunction:easeOut];
217 [positionAnimation setDuration:ios::material::kDuration1];
218 [positionAnimation setKeyTimes:@[ @0, @0.2, @0.5, @1 ]];
219
220 CAMediaTimingFunction* linear = TimingFunction(ios::material::CurveLinear);
221 CAAnimation* fadeAnimation = OpacityAnimationMake(0, 1);
222 [fadeAnimation setDuration:ios::material::kDuration2];
223 [fadeAnimation setTimingFunction:linear];
224 [fadeAnimation setBeginTime:ios::material::kDuration2];
225
226 CALayer* layer = [popupContainer_ layer];
227 [layer addAnimation:AnimationGroupMake(
228 @[ scaleAnimation, positionAnimation, fadeAnimation ])
229 forKey:@"popup-in"];
230 }
231
232 - (void)animateOutToPoint:(CGPoint)destination
233 completion:(void (^)(void))completion {
234 CGPoint source = [[popupContainer_ layer] position];
235
236 CGPoint midPoint = CGPointZero;
237 midPoint.x = destination.x;
238 midPoint.y = source.y - 0.8 * fabs(destination.x - source.x);
239
240 CATransform3D scaleTransform =
241 CATransform3DMakeScale(kPopoverScaleFactor, kPopoverScaleFactor, 1);
242
243 CAMediaTimingFunction* easeIn = TimingFunction(ios::material::CurveEaseIn);
244 [CATransaction begin];
245 [CATransaction setAnimationTimingFunction:easeIn];
246 [CATransaction setAnimationDuration:ios::material::kDuration2];
247
248 base::WeakNSObject<PopupMenuController> weakSelf(self);
249 [CATransaction setCompletionBlock:^{
250 if (completion)
251 completion();
252 }];
253
254 NSValue* sourceScaleValue =
255 [NSValue valueWithCATransform3D:CATransform3DIdentity];
256
257 CABasicAnimation* scaleAnimation =
258 [CABasicAnimation animationWithKeyPath:@"transform"];
259 [scaleAnimation setFromValue:sourceScaleValue];
260 [scaleAnimation setToValue:[NSValue valueWithCATransform3D:scaleTransform]];
261
262 CABasicAnimation* positionAnimation =
263 [CABasicAnimation animationWithKeyPath:@"position"];
264 [positionAnimation setFromValue:[NSValue valueWithCGPoint:source]];
265 [positionAnimation setToValue:[NSValue valueWithCGPoint:destination]];
266
267 CABasicAnimation* fadeAnimation =
268 [CABasicAnimation animationWithKeyPath:@"opacity"];
269 [fadeAnimation setFromValue:@1];
270 [fadeAnimation setToValue:@0];
271
272 CALayer* layer = [popupContainer_ layer];
273 [layer addAnimation:AnimationGroupMake(
274 @[ scaleAnimation, positionAnimation, fadeAnimation ])
275 forKey:@"out"];
276
277 [CATransaction commit];
278 }
279
280 #pragma mark -
281 #pragma mark PopupMenuViewDelegate
282
283 - (void)dismissPopupMenu {
284 [delegate_ dismissPopupMenu:self];
285 }
286
287 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/popup_menu/popup_menu_controller.h ('k') | ios/chrome/browser/ui/popup_menu/popup_menu_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698