Skip to content

Commit

Permalink
Rework dismissal blocks to allow for interaction with a notice that s…
Browse files Browse the repository at this point in the history
…upport interactive dismissal and a timeout.

In these cases, the display interval is managed by an NSTimer instead of the UIView animation delay property. This is because of two factors:
1. The UIView animation blocks by default disable interaction with the views.
2. If you enable the option to support interaction, the frame of the button matches the final destination frame instead of the current visible frame. This causes hit tests to fail and for all intents and purposes makes the notice view an untappable target.
  • Loading branch information
blakewatters committed Nov 13, 2012
1 parent 624e8ed commit e6e8668
Showing 1 changed file with 25 additions and 10 deletions.
35 changes: 25 additions & 10 deletions NoticeView/WBNoticeView/WBNoticeView.m
Expand Up @@ -18,11 +18,11 @@ @interface WBNoticeView ()
@property(nonatomic, assign) CGFloat hiddenYOrigin;
@property(nonatomic, strong) WBNoticeView *currentNotice;
@property(nonatomic, copy) void (^dismissalBlock)(BOOL dismissedInteractively);
@property(nonatomic, strong) NSTimer *displayTimer;

- (void)dismissNoticeWithDuration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
hiddenYOrigin:(CGFloat)hiddenYOrigin
interactively:(BOOL)interactively;
hiddenYOrigin:(CGFloat)hiddenYOrigin;
- (void)cleanup;

@end
Expand Down Expand Up @@ -101,25 +101,26 @@ - (void)displayNotice
} completion:^ (BOOL finished) {
if (finished) {
// if it's not sticky, hide it automatically
if (NO == self.isSticky) {
if (self.tapToDismissEnabled && !self.isSticky) {
// Schedule a timer
self.displayTimer = [NSTimer scheduledTimerWithTimeInterval:self.delay target:self selector:@selector(dismissAfterTimerExpiration) userInfo:nil repeats:NO];
} else if (!self.isSticky) {
// Display for a while, then hide it again
[self dismissNoticeWithDuration:self.duration delay:self.delay hiddenYOrigin:self.hiddenYOrigin interactively:NO];
[self dismissNoticeWithDuration:self.duration delay:self.delay hiddenYOrigin:self.hiddenYOrigin];
}
}
}];
}

- (void)dismissNoticeWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay hiddenYOrigin:(CGFloat)hiddenYOrigin interactively:(BOOL)interactively
- (void)dismissNoticeWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay hiddenYOrigin:(CGFloat)hiddenYOrigin
{
[UIView animateWithDuration:duration delay:delay options:UIViewAnimationOptionCurveEaseOut animations:^ {
CGRect newFrame = self.gradientView.frame;
newFrame.origin.y = hiddenYOrigin;
self.gradientView.frame = newFrame;
} completion:^ (BOOL finished) {
if (finished) {
if (self.dismissalBlock) {
self.dismissalBlock(interactively);
}
if (self.dismissalBlock) self.dismissalBlock(NO);
// Cleanup
[self cleanup];
}
Expand All @@ -128,18 +129,32 @@ - (void)dismissNoticeWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval

- (void)dismissNotice
{
[self dismissNoticeWithDuration:self.duration delay:self.delay hiddenYOrigin:self.hiddenYOrigin interactively:NO];
[self.displayTimer invalidate];
[self dismissNoticeWithDuration:self.duration delay:self.delay hiddenYOrigin:self.hiddenYOrigin];
}

- (void)dismissNoticeInteractively
{
[self dismissNoticeWithDuration:self.duration delay:self.delay hiddenYOrigin:self.hiddenYOrigin interactively:YES];
[self.displayTimer invalidate];
if (self.dismissalBlock) {
self.dismissalBlock(YES);

// Clear the reference to the dismissal block so that the animation does invoke the block a second time
self.dismissalBlock = nil;
}
[self dismissNoticeWithDuration:self.duration delay:self.delay hiddenYOrigin:self.hiddenYOrigin];
}

- (void)dismissAfterTimerExpiration
{
[self dismissNoticeWithDuration:self.duration delay:0.0 hiddenYOrigin:self.hiddenYOrigin];
}

#pragma mark -

- (void)cleanup
{
[self.displayTimer invalidate];
[self.gradientView removeFromSuperview];
self.gradientView = nil;
self.titleLabel = nil;
Expand Down

0 comments on commit e6e8668

Please sign in to comment.