@@ -54,11 +54,6 @@ @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-
6257/* *
6358 The object which will notify us of changes in the keyboard position.
6459 */
@@ -88,6 +83,16 @@ @interface MDCSnackbarOverlayView ()
8883 */
8984@property (nonatomic ) NSTimeInterval rotationDuration;
9085
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+
9196@end
9297
9398@implementation MDCSnackbarOverlayView
@@ -272,13 +277,26 @@ - (void)setSnackbarView:(MDCSnackbarMessageView *)snackbarView {
272277 }
273278
274279 // Always pin the snackbar to the bottom of the container.
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]];
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];
282300
283301 // Always limit the height of the snackbar.
284302 [container
@@ -408,40 +426,44 @@ - (void)fadeInsnackbarView:(MDCSnackbarMessageView *)snackbarView
408426#pragma mark - Slide Animation
409427
410428- (void )slideMessageView : (MDCSnackbarMessageView *)snackbarView
411- fromY : (CGFloat)fromY
412- toY : (CGFloat)toY
429+ onscreen : (BOOL )onscreen
413430 fromContentOpacity : (CGFloat)fromContentOpacity
414431 toContentOpacity : (CGFloat)toContentOpacity
415- notificationFrame : (CGRect)notificationFrame
416432 completion : (void (^)(void ))completion {
417- // Save off @c completion for when the CAAnimation completes .
418- self. pendingCompletionBlock = completion ;
419-
420- [CATransaction begin ];
433+ // Prepare to move the snackbar .
434+ _snackbarOnscreenConstraint. active = onscreen ;
435+ _snackbarOffscreenConstraint. active = !onscreen;
436+ [_containingView setNeedsUpdateConstraints ];
421437
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 =
438+ CAMediaTimingFunction *timingFunction =
430439 [CAMediaTimingFunction mdc_functionWithType: MDCAnimationTimingFunctionEaseInOut];
431-
432- [snackbarView.layer addAnimation: translationAnimation forKey: @" translation" ];
440+ [CATransaction begin ];
441+ [CATransaction setAnimationTimingFunction: timingFunction];
442+
443+ // We use UIView animation inside a CATransaction in order to use the custom animation curve.
444+ [UIView animateWithDuration: MDCSnackbarTransitionDuration
445+ delay: 0
446+ options: UIViewAnimationOptionCurveEaseInOut
447+ animations: ^{
448+ // Trigger snackbar animation.
449+ [_containingView layoutIfNeeded ];
450+ } completion: ^(BOOL finished) {
451+ if (completion) {
452+ completion ();
453+ }
454+ }];
433455
434456 [snackbarView animateContentOpacityFrom: fromContentOpacity
435457 to: toContentOpacity
436- duration: translationAnimation.duration
437- timingFunction: translationAnimation. timingFunction];
458+ duration: MDCSnackbarTransitionDuration
459+ timingFunction: timingFunction];
438460 [CATransaction commit ];
439461
440462 // Notify the overlay system.
441- [self notifyOverlayChangeWithFrame: notificationFrame
442- duration: translationAnimation.duration
463+ [self notifyOverlayChangeWithFrame: [ self snackbarRectInScreenCoordinates ]
464+ duration: MDCSnackbarTransitionDuration
443465 curve: 0
444- timingFunction: translationAnimation. timingFunction];
466+ timingFunction: timingFunction];
445467}
446468
447469- (void )slideInMessageView : (MDCSnackbarMessageView *)snackbarView
@@ -450,11 +472,9 @@ - (void)slideInMessageView:(MDCSnackbarMessageView *)snackbarView
450472 [self triggerSnackbarLayoutChange ];
451473
452474 [self slideMessageView: snackbarView
453- fromY: snackbarView.bounds.size.height + [self staticBottomMargin ]
454- toY: 0 .0f
475+ onscreen: YES
455476 fromContentOpacity: 0
456477 toContentOpacity: 1
457- notificationFrame: [self snackbarRectInScreenCoordinates ]
458478 completion: completion];
459479}
460480
@@ -464,25 +484,12 @@ - (void)slideOutMessageView:(MDCSnackbarMessageView *)snackbarView
464484 [self triggerSnackbarLayoutChange ];
465485
466486 [self slideMessageView: snackbarView
467- fromY: 0 .0f
468- toY: snackbarView.bounds.size.height + [self staticBottomMargin ]
487+ onscreen: NO
469488 fromContentOpacity: 1
470489 toContentOpacity: 0
471- notificationFrame: CGRectNull
472490 completion: completion];
473491}
474492
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-
486493#pragma mark - Keyboard Notifications
487494
488495- (void )updatesnackbarPositionWithKeyboardUserInfo : (NSDictionary *)userInfo {
0 commit comments