Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 57 additions & 47 deletions components/Snackbar/src/private/MDCSnackbarOverlayView.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ @interface MDCSnackbarOverlayView ()
*/
@property(nonatomic) MDCSnackbarMessageView *snackbarView;

/**
Storage for a completion block that is waiting for a CAAnimation to finish.
*/
@property(nonatomic, copy) void (^pendingCompletionBlock)(void);

/**
The object which will notify us of changes in the keyboard position.
*/
Expand Down Expand Up @@ -88,6 +83,16 @@ @interface MDCSnackbarOverlayView ()
*/
@property(nonatomic) NSTimeInterval rotationDuration;

/**
The constraint used to pin the bottom of the snackbar to the bottom of the screen.
*/
@property(nonatomic) NSLayoutConstraint *snackbarOnscreenConstraint;

/**
The constraint used to pin the top of the snackbar to the bottom of the screen.
*/
@property(nonatomic) NSLayoutConstraint *snackbarOffscreenConstraint;

@end

@implementation MDCSnackbarOverlayView
Expand Down Expand Up @@ -272,13 +277,26 @@ - (void)setSnackbarView:(MDCSnackbarMessageView *)snackbarView {
}

// Always pin the snackbar to the bottom of the container.
[container addConstraint:[NSLayoutConstraint constraintWithItem:snackbarView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:container
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-bottomMargin]];
_snackbarOnscreenConstraint = [NSLayoutConstraint constraintWithItem:snackbarView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:container
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-bottomMargin];
_snackbarOnscreenConstraint.active = NO; // snackbar starts off-screen.
_snackbarOnscreenConstraint.priority = UILayoutPriorityDefaultHigh;
[container addConstraint:_snackbarOnscreenConstraint];

_snackbarOffscreenConstraint = [NSLayoutConstraint constraintWithItem:snackbarView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:container
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-bottomMargin];
_snackbarOffscreenConstraint.active = YES;
[container addConstraint:_snackbarOffscreenConstraint];

// Always limit the height of the snackbar.
[container
Expand Down Expand Up @@ -408,40 +426,45 @@ - (void)fadeInsnackbarView:(MDCSnackbarMessageView *)snackbarView
#pragma mark - Slide Animation

- (void)slideMessageView:(MDCSnackbarMessageView *)snackbarView
fromY:(CGFloat)fromY
toY:(CGFloat)toY
onscreen:(BOOL)onscreen
fromContentOpacity:(CGFloat)fromContentOpacity
toContentOpacity:(CGFloat)toContentOpacity
notificationFrame:(CGRect)notificationFrame
completion:(void (^)(void))completion {
// Save off @c completion for when the CAAnimation completes.
self.pendingCompletionBlock = completion;
// Prepare to move the snackbar.
_snackbarOnscreenConstraint.active = onscreen;
_snackbarOffscreenConstraint.active = !onscreen;
[_containingView setNeedsUpdateConstraints];

[CATransaction begin];

// Move the snackbar.
CABasicAnimation *translationAnimation =
[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
translationAnimation.duration = MDCSnackbarTransitionDuration;
translationAnimation.fromValue = @(fromY);
translationAnimation.toValue = @(toY);
translationAnimation.delegate = self;
translationAnimation.timingFunction =
CAMediaTimingFunction *timingFunction =
[CAMediaTimingFunction mdc_functionWithType:MDCAnimationTimingFunctionEaseInOut];

[snackbarView.layer addAnimation:translationAnimation forKey:@"translation"];
[CATransaction begin];
[CATransaction setAnimationTimingFunction:timingFunction];

// We use UIView animation inside a CATransaction in order to use the custom animation curve.
[UIView animateWithDuration:MDCSnackbarTransitionDuration
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
// Trigger snackbar animation.
[_containingView layoutIfNeeded];
} completion:^(BOOL finished) {
if (completion) {
completion();
}
}];

[snackbarView animateContentOpacityFrom:fromContentOpacity
to:toContentOpacity
duration:translationAnimation.duration
timingFunction:translationAnimation.timingFunction];
duration:MDCSnackbarTransitionDuration
timingFunction:timingFunction];
[CATransaction commit];

// Notify the overlay system.
[self notifyOverlayChangeWithFrame:notificationFrame
duration:translationAnimation.duration
duration:MDCSnackbarTransitionDuration
curve:0
timingFunction:translationAnimation.timingFunction];
timingFunction:timingFunction];
}

- (void)slideInMessageView:(MDCSnackbarMessageView *)snackbarView
Expand All @@ -450,8 +473,7 @@ - (void)slideInMessageView:(MDCSnackbarMessageView *)snackbarView
[self triggerSnackbarLayoutChange];

[self slideMessageView:snackbarView
fromY:snackbarView.bounds.size.height + [self staticBottomMargin]
toY:0.0f
onscreen:YES
fromContentOpacity:0
toContentOpacity:1
notificationFrame:[self snackbarRectInScreenCoordinates]
Expand All @@ -464,25 +486,13 @@ - (void)slideOutMessageView:(MDCSnackbarMessageView *)snackbarView
[self triggerSnackbarLayoutChange];

[self slideMessageView:snackbarView
fromY:0.0f
toY:snackbarView.bounds.size.height + [self staticBottomMargin]
onscreen:NO
fromContentOpacity:1
toContentOpacity:0
notificationFrame:CGRectNull
completion:completion];
}

#pragma mark - CAAnimationDelegate

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
void (^block)(void) = self.pendingCompletionBlock;
self.pendingCompletionBlock = nil;

if (block) {
block();
}
}

#pragma mark - Keyboard Notifications

- (void)updatesnackbarPositionWithKeyboardUserInfo:(NSDictionary *)userInfo {
Expand Down