@@ -54,6 +54,11 @@ @interface MDCSnackbarOverlayView ()
5454 */
5555@property (nonatomic ) MDCSnackbarMessageView *snackbarView;
5656
57+ /* *
58+ Storage for a completion block that is waiting for a CAAnimation to finish.
59+ */
60+ @property (nonatomic , copy ) void (^pendingCompletionBlock)(void );
61+
5762/* *
5863 The object which will notify us of changes in the keyboard position.
5964 */
@@ -83,16 +88,6 @@ @interface MDCSnackbarOverlayView ()
8388 */
8489@property (nonatomic ) NSTimeInterval rotationDuration;
8590
86- /* *
87- The constraint used to pin the bottom of the snackbar to the bottom of the screen.
88- */
89- @property (nonatomic ) NSLayoutConstraint *snackbarOnscreenConstraint;
90-
91- /* *
92- The constraint used to pin the top of the snackbar to the bottom of the screen.
93- */
94- @property (nonatomic ) NSLayoutConstraint *snackbarOffscreenConstraint;
95-
9691@end
9792
9893@implementation MDCSnackbarOverlayView
@@ -277,26 +272,13 @@ - (void)setSnackbarView:(MDCSnackbarMessageView *)snackbarView {
277272 }
278273
279274 // Always pin the snackbar to the bottom of the container.
280- _snackbarOnscreenConstraint = [NSLayoutConstraint constraintWithItem: snackbarView
281- attribute: NSLayoutAttributeBottom
282- relatedBy: NSLayoutRelationEqual
283- toItem: container
284- attribute: NSLayoutAttributeBottom
285- multiplier: 1.0
286- constant: -bottomMargin];
287- _snackbarOnscreenConstraint.active = NO ; // snackbar starts off-screen.
288- _snackbarOnscreenConstraint.priority = UILayoutPriorityDefaultHigh;
289- [container addConstraint: _snackbarOnscreenConstraint];
290-
291- _snackbarOffscreenConstraint = [NSLayoutConstraint constraintWithItem: snackbarView
292- attribute: NSLayoutAttributeTop
293- relatedBy: NSLayoutRelationEqual
294- toItem: container
295- attribute: NSLayoutAttributeBottom
296- multiplier: 1.0
297- constant: -bottomMargin];
298- _snackbarOffscreenConstraint.active = YES ;
299- [container addConstraint: _snackbarOffscreenConstraint];
275+ [container addConstraint: [NSLayoutConstraint constraintWithItem: snackbarView
276+ attribute: NSLayoutAttributeBottom
277+ relatedBy: NSLayoutRelationEqual
278+ toItem: container
279+ attribute: NSLayoutAttributeBottom
280+ multiplier: 1.0
281+ constant: -bottomMargin]];
300282
301283 // Always limit the height of the snackbar.
302284 [container
@@ -426,45 +408,40 @@ - (void)fadeInsnackbarView:(MDCSnackbarMessageView *)snackbarView
426408#pragma mark - Slide Animation
427409
428410- (void )slideMessageView : (MDCSnackbarMessageView *)snackbarView
429- onscreen : (BOOL )onscreen
411+ fromY : (CGFloat)fromY
412+ toY : (CGFloat)toY
430413 fromContentOpacity : (CGFloat)fromContentOpacity
431414 toContentOpacity : (CGFloat)toContentOpacity
432415 notificationFrame : (CGRect)notificationFrame
433416 completion : (void (^)(void ))completion {
434- // Prepare to move the snackbar.
435- _snackbarOnscreenConstraint.active = onscreen;
436- _snackbarOffscreenConstraint.active = !onscreen;
437- [_containingView setNeedsUpdateConstraints ];
417+ // Save off @c completion for when the CAAnimation completes.
418+ self.pendingCompletionBlock = completion;
438419
439- CAMediaTimingFunction *timingFunction =
440- [CAMediaTimingFunction mdc_functionWithType: MDCAnimationTimingFunctionEaseInOut];
441420 [CATransaction begin ];
442- [CATransaction setAnimationTimingFunction: timingFunction];
443-
444- // We use UIView animation inside a CATransaction in order to use the custom animation curve.
445- [UIView animateWithDuration: MDCSnackbarTransitionDuration
446- delay: 0
447- options: UIViewAnimationOptionCurveEaseInOut
448- animations: ^{
449- // Trigger snackbar animation.
450- [_containingView layoutIfNeeded ];
451- } completion: ^(BOOL finished) {
452- if (completion) {
453- completion ();
454- }
455- }];
421+
422+ // Move the snackbar.
423+ CABasicAnimation *translationAnimation =
424+ [CABasicAnimation animationWithKeyPath: @" transform.translation.y" ];
425+ translationAnimation.duration = MDCSnackbarTransitionDuration;
426+ translationAnimation.fromValue = @(fromY);
427+ translationAnimation.toValue = @(toY);
428+ translationAnimation.delegate = self;
429+ translationAnimation.timingFunction =
430+ [CAMediaTimingFunction mdc_functionWithType: MDCAnimationTimingFunctionEaseInOut];
431+
432+ [snackbarView.layer addAnimation: translationAnimation forKey: @" translation" ];
456433
457434 [snackbarView animateContentOpacityFrom: fromContentOpacity
458435 to: toContentOpacity
459- duration: MDCSnackbarTransitionDuration
460- timingFunction: timingFunction];
436+ duration: translationAnimation.duration
437+ timingFunction: translationAnimation. timingFunction];
461438 [CATransaction commit ];
462439
463440 // Notify the overlay system.
464441 [self notifyOverlayChangeWithFrame: notificationFrame
465- duration: MDCSnackbarTransitionDuration
442+ duration: translationAnimation.duration
466443 curve: 0
467- timingFunction: timingFunction];
444+ timingFunction: translationAnimation. timingFunction];
468445}
469446
470447- (void )slideInMessageView : (MDCSnackbarMessageView *)snackbarView
@@ -473,7 +450,8 @@ - (void)slideInMessageView:(MDCSnackbarMessageView *)snackbarView
473450 [self triggerSnackbarLayoutChange ];
474451
475452 [self slideMessageView: snackbarView
476- onscreen: YES
453+ fromY: snackbarView.bounds.size.height + [self staticBottomMargin ]
454+ toY: 0 .0f
477455 fromContentOpacity: 0
478456 toContentOpacity: 1
479457 notificationFrame: [self snackbarRectInScreenCoordinates ]
@@ -486,13 +464,25 @@ - (void)slideOutMessageView:(MDCSnackbarMessageView *)snackbarView
486464 [self triggerSnackbarLayoutChange ];
487465
488466 [self slideMessageView: snackbarView
489- onscreen: NO
467+ fromY: 0 .0f
468+ toY: snackbarView.bounds.size.height + [self staticBottomMargin ]
490469 fromContentOpacity: 1
491470 toContentOpacity: 0
492471 notificationFrame: CGRectNull
493472 completion: completion];
494473}
495474
475+ #pragma mark - CAAnimationDelegate
476+
477+ - (void )animationDidStop : (CAAnimation *)anim finished : (BOOL )flag {
478+ void (^block)(void ) = self.pendingCompletionBlock ;
479+ self.pendingCompletionBlock = nil ;
480+
481+ if (block) {
482+ block ();
483+ }
484+ }
485+
496486#pragma mark - Keyboard Notifications
497487
498488- (void )updatesnackbarPositionWithKeyboardUserInfo : (NSDictionary *)userInfo {
0 commit comments