Skip to content

Commit

Permalink
[Snackbar] Add ability to set presentation host view on specific mess…
Browse files Browse the repository at this point in the history
…age.

This allows finer granularity to set specific snackbar messages under certain views.

PiperOrigin-RevId: 309919536
  • Loading branch information
yarneo authored and material-automation committed May 5, 2020
1 parent 14bdd27 commit ec84eb9
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 12 deletions.
24 changes: 15 additions & 9 deletions components/Snackbar/examples/SnackbarSimpleExample.m
Expand Up @@ -35,15 +35,10 @@ - (void)viewDidLoad {
[[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201804];
}
[self setupExampleViews:@[
@"Simple Snackbar",
@"Snackbar with Action Button",
@"Snackbar with Long Text",
@"Attributed Text Example",
@"Color Themed Snackbar",
@"Customize Font Example",
@"De-Customize Example",
@"Customized Message Using Block",
@"Non Transient Snackbar",
@"Simple Snackbar", @"Snackbar with Action Button", @"Snackbar with Long Text",
@"Attributed Text Example", @"Color Themed Snackbar", @"Customize Font Example",
@"De-Customize Example", @"Customized Message Using Block", @"Non Transient Snackbar",
@"Snackbar Presented On Custom View"
]];
self.title = @"Snackbar";
_legacyMode = YES;
Expand Down Expand Up @@ -204,6 +199,14 @@ - (void)showNonTransientSnackbar:(id)sender {
[MDCSnackbarManager showMessage:message];
}

- (void)showSimpleSnackbarOnCustomPresentationHostView:(id)sender {
MDCSnackbarMessage *message = [[MDCSnackbarMessage alloc] init];
message.text = @"Snackbar Message";
message.focusOnShow = YES;
message.presentationHostViewOverride = self.collectionView;
[MDCSnackbarManager showMessage:message];
}

#pragma mark - UICollectionView

- (void)collectionView:(UICollectionView *)collectionView
Expand Down Expand Up @@ -237,6 +240,9 @@ - (void)collectionView:(UICollectionView *)collectionView
case 8:
[self showNonTransientSnackbar:nil];
break;
case 9:
[self showSimpleSnackbarOnCustomPresentationHostView:nil];
break;
default:
break;
}
Expand Down
8 changes: 5 additions & 3 deletions components/Snackbar/src/MDCSnackbarManager.m
Expand Up @@ -237,7 +237,7 @@ - (void)displaySnackbarViewForMessage:(MDCSnackbarMessage *)message {
self.currentSnackbar = snackbarView;
self.overlayView.accessibilityViewIsModal = snackbarView.accessibilityViewIsModal;
self.overlayView.hidden = NO;
[self activateOverlay:self.overlayView];
[self activateOverlay:self.overlayView forMessage:message];

// Once the Snackbar has finished animating on screen, start the automatic dismiss timeout, but
// only if the user isn't running VoiceOver.
Expand Down Expand Up @@ -349,11 +349,13 @@ - (BOOL)isSnackbarTransient:(MDCSnackbarMessageView *)snackbarView {

#pragma mark - Overlay Activation

- (void)activateOverlay:(UIView *)overlay {
- (void)activateOverlay:(UIView *)overlay forMessage:(MDCSnackbarMessage *)message {
UIWindow *window = [self bestGuessWindow];
UIView *targetView = nil;

if (self.presentationHostView) {
if (message.presentationHostViewOverride) {
targetView = message.presentationHostViewOverride;
} else if (self.presentationHostView) {
targetView = self.presentationHostView;
} else if ([window isKindOfClass:[MDCOverlayWindow class]]) {
// If the application's window is an overlay window, take advantage of it. Otherwise, just add
Expand Down
12 changes: 12 additions & 0 deletions components/Snackbar/src/MDCSnackbarMessage.h
Expand Up @@ -198,6 +198,18 @@ extern NSString *__nonnull const MDCSnackbarMessageBoldAttributeName;
*/
@property(nonatomic) BOOL automaticallyDismisses;

/**
MDCSnackbarManager will display the snackbar message in this view.
Call this method to choose where in the view hierarchy this specific snackbar message will be
presented. This method should be called only in cases where the default behavior is unable to find
the correct view to place the snackbar message in. Furthermore, please set this property only if
this message is a special case and needs to be presented on a view different than the other
messages of this specific snackbar manager. Otherwise, please set the presentation host view by
using MDCSnackbarManager's @c setPresentationHostView.
*/
@property(nonatomic, weak, nullable) UIView *presentationHostViewOverride;

@end

/**
Expand Down
1 change: 1 addition & 0 deletions components/Snackbar/src/MDCSnackbarMessage.m
Expand Up @@ -74,6 +74,7 @@ - (instancetype)copyWithZone:(__unused NSZone *)zone {
copy.focusOnShow = self.focusOnShow;
copy.elementToFocusOnDismiss = self.elementToFocusOnDismiss;
copy.automaticallyDismisses = self.automaticallyDismisses;
copy.presentationHostViewOverride = self.presentationHostViewOverride;

// Unfortunately there's not really a concept of 'copying' a block (in the same way you would copy
// a string, for example). A block's pointer is immutable once it is created and copied to the
Expand Down
20 changes: 20 additions & 0 deletions components/Snackbar/tests/unit/MDCSnackbarMessageViewTests.m
Expand Up @@ -547,4 +547,24 @@ - (void)testSnackbarDidDisappearDelegateCalled {
[self waitForExpectationsWithTimeout:3 handler:nil];
}

- (void)testSettingPresentationHostViewOverrideDisplaysSnackbarInCorrectView {
// Given
UIView *customView = [[UIView alloc] init];
self.message.presentationHostViewOverride = customView;

// When
[self.manager showMessage:self.message];
XCTestExpectation *expectation = [self expectationWithDescription:@"completed"];
dispatch_time_t popTime =
dispatch_time(DISPATCH_TIME_NOW, (int64_t)((CGFloat)0.1 * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^{
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:3 handler:nil];

// Then
XCTAssertTrue([customView.subviews count] > 0);
XCTAssertEqual([customView.subviews.firstObject class], [MDCSnackbarOverlayView class]);
}

@end

0 comments on commit ec84eb9

Please sign in to comment.