From 056064c48152b743098b1a50d759fb6f91c7918f Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 28 Aug 2013 11:57:26 -0400 Subject: [PATCH] added tap handler. fixes #2 By default, supplying a tap handler will disable ```allowTapToDismiss``` on this particular banner. If you want to reinstate this behavior alongside the tap handler, you can call ```[[ALAlertBannerManager sharedManager] hideAlertBanner:alertBanner];``` in ```tappedBlock()```. --- ALAlertBanner/ALAlertBannerManager.h | 43 ++++++++++++++++--- ALAlertBanner/ALAlertBannerManager.m | 31 ++++++++++--- ALAlertBanner/ALAlertBannerView.h | 1 + ALAlertBanner/ALAlertBannerView.m | 24 ++++++----- .../ALAlertBannerDemo/ViewController.m | 7 ++- 5 files changed, 83 insertions(+), 23 deletions(-) diff --git a/ALAlertBanner/ALAlertBannerManager.h b/ALAlertBanner/ALAlertBannerManager.h index 2f8968f..a794d9b 100644 --- a/ALAlertBanner/ALAlertBannerManager.h +++ b/ALAlertBanner/ALAlertBannerManager.h @@ -28,27 +28,37 @@ @interface ALAlertBannerManager : NSObject /** - Length of time in seconds that a banner should show before auto-hiding. Default is 3.5 seconds. A value <= 0 will disable auto-hiding. + Length of time in seconds that a banner should show before auto-hiding. + + Default value is 3.5 seconds. A value <= 0 will disable auto-hiding. */ @property (nonatomic) NSTimeInterval secondsToShow; /** - The length of time it takes a banner to transition on-screen. Default is 0.25 seconds. + The length of time it takes a banner to transition on-screen. + + Default value is 0.25 seconds. */ @property (nonatomic) NSTimeInterval showAnimationDuration; /** - The length of time it takes a banner to transition off-screen. Default is 0.2 seconds. + The length of time it takes a banner to transition off-screen. + + Default value is 0.2 seconds. */ @property (nonatomic) NSTimeInterval hideAnimationDuration; /** - Banner opacity, between 0 and 1. Default value is 0.93f. + Banner opacity, between 0 and 1. + + Default value is 0.93f. */ @property (nonatomic, assign) CGFloat bannerOpacity; /** - Tapping on a banner will dismiss it early. Default is YES. + Tapping on a banner will dismiss it early. + + Default value is YES. If you supply a tappedHandler in one of the appropriate methods, this will be set to NO for that specific banner. */ @property (nonatomic, assign) BOOL allowTapToDismiss; @@ -58,10 +68,31 @@ +(ALAlertBannerManager*)sharedManager; /** - The default (and only) way to display a banner. All parameters except subtitle must not be nil. + The default methods to display a banner. */ +-(void)showAlertBannerInView:(UIView*)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString*)title; + -(void)showAlertBannerInView:(UIView*)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString*)title subtitle:(NSString*)subtitle; +/** + Optional method to set the secondsToShow duration on a per-banner basis. + */ +-(void)showAlertBannerInView:(UIView*)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString*)title subtitle:(NSString*)subtitle hideAfter:(NSTimeInterval)secondsToShow; + +/** + Optional methods to handle a tap on a banner. + + By default, supplying a tap handler will disable allowTapToDismiss on this particular banner. If you want to reinstate this behavior alongside the tap handler, you can call `[[ALAlertBannerManager sharedManager] hideAlertBanner:alertBanner];` in tappedBlock(). + */ +-(void)showAlertBannerInView:(UIView*)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString*)title subtitle:(NSString*)subtitle tappedHandler:(void(^)(ALAlertBannerView *alertBanner))tappedBlock; + +-(void)showAlertBannerInView:(UIView*)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString*)title subtitle:(NSString*)subtitle hideAfter:(NSTimeInterval)secondsToShow tappedHandler:(void(^)(ALAlertBannerView *alertBanner))tappedBlock; + +/** + Immediately hide a specific alert banner. + */ +-(void)hideAlertBanner:(ALAlertBannerView *)alertBanner; + /** Returns an array of all banners within a certain view. */ diff --git a/ALAlertBanner/ALAlertBannerManager.m b/ALAlertBanner/ALAlertBannerManager.m index d23cdf2..fc4a254 100644 --- a/ALAlertBanner/ALAlertBannerManager.m +++ b/ALAlertBanner/ALAlertBannerManager.m @@ -102,25 +102,46 @@ -(id)init return self; } +-(void)showAlertBannerInView:(UIView *)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString *)title +{ + [self showAlertBannerInView:view style:style position:position title:title subtitle:nil hideAfter:self.secondsToShow tappedHandler:nil]; +} + -(void)showAlertBannerInView:(UIView *)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString *)title subtitle:(NSString *)subtitle { + [self showAlertBannerInView:view style:style position:position title:title subtitle:subtitle hideAfter:self.secondsToShow tappedHandler:nil]; +} + +-(void)showAlertBannerInView:(UIView *)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString *)title subtitle:(NSString *)subtitle hideAfter:(NSTimeInterval)secondsToShow +{ + [self showAlertBannerInView:view style:style position:position title:title subtitle:subtitle hideAfter:secondsToShow tappedHandler:nil]; +} + +-(void)showAlertBannerInView:(UIView *)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString *)title subtitle:(NSString *)subtitle tappedHandler:(void (^)(ALAlertBannerView *))tappedBlock +{ + [self showAlertBannerInView:view style:style position:position title:title subtitle:subtitle hideAfter:self.secondsToShow tappedHandler:tappedBlock]; +} + +-(void)showAlertBannerInView:(UIView *)view style:(ALAlertBannerStyle)style position:(ALAlertBannerPosition)position title:(NSString *)title subtitle:(NSString *)subtitle hideAfter:(NSTimeInterval)secondsToShow tappedHandler:(void (^)(ALAlertBannerView *))tappedBlock +{ ALAlertBannerView *alertBanner = [ALAlertBannerView alertBannerForView:view style:style position:position title:title subtitle:subtitle]; alertBanner.delegate = self; alertBanner.tag = arc4random_uniform(SHRT_MAX); alertBanner.showAnimationDuration = self.showAnimationDuration; alertBanner.hideAnimationDuration = self.hideAnimationDuration; - alertBanner.allowTapToDismiss = self.allowTapToDismiss; + alertBanner.allowTapToDismiss = tappedBlock ? NO : self.allowTapToDismiss; alertBanner.isScheduledToHide = NO; alertBanner.bannerOpacity = self.bannerOpacity; + alertBanner.tappedBlock = tappedBlock; //keep track of all views we've added banners to, to deal with rotation events and hideAllAlertBanners if (![self.bannerViews containsObject:view]) [self.bannerViews addObject:view]; - [self showAlertBanner:alertBanner]; + [self showAlertBanner:alertBanner hideAfter:secondsToShow]; } --(void)showAlertBanner:(ALAlertBannerView*)alertBanner +-(void)showAlertBanner:(ALAlertBannerView*)alertBanner hideAfter:(NSTimeInterval)delay { dispatch_semaphore_t semaphore; switch (alertBanner.position) { @@ -139,8 +160,8 @@ -(void)showAlertBanner:(ALAlertBannerView*)alertBanner dispatch_async(dispatch_get_main_queue(), ^{ [alertBanner show]; - if (self.secondsToShow > 0) - [self performSelector:@selector(hideAlertBanner:) withObject:alertBanner afterDelay:self.secondsToShow]; + if (delay > 0) + [self performSelector:@selector(hideAlertBanner:) withObject:alertBanner afterDelay:delay]; }); }); } diff --git a/ALAlertBanner/ALAlertBannerView.h b/ALAlertBanner/ALAlertBannerView.h index 10c2138..0f9b41c 100644 --- a/ALAlertBanner/ALAlertBannerView.h +++ b/ALAlertBanner/ALAlertBannerView.h @@ -90,6 +90,7 @@ typedef enum { @property (nonatomic) BOOL isScheduledToHide; @property (nonatomic) BOOL allowTapToDismiss; +@property (nonatomic, copy) void(^tappedBlock)(ALAlertBannerView *); @property (nonatomic) NSTimeInterval fadeInDuration; @property (nonatomic) BOOL showShadow; diff --git a/ALAlertBanner/ALAlertBannerView.m b/ALAlertBanner/ALAlertBannerView.m index 73ec7aa..c481590 100644 --- a/ALAlertBanner/ALAlertBannerView.m +++ b/ALAlertBanner/ALAlertBannerView.m @@ -38,17 +38,13 @@ this software and associated documentation files (the "Software"), to deal in //macros referenced from MBProgressHUD. cheers to @matej #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 - #define AL_SINGLELINE_TEXT_HEIGHT(text, font) [text length] > 0 ? [text sizeWithAttributes:nil].height : 0.f; -#else - #define AL_SINGLELINE_TEXT_HEIGHT(text, font) [text length] > 0 ? [text sizeWithFont:font].height : 0.f; -#endif - -#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 + #define AL_SINGLELINE_TEXT_HEIGHT(text, font) [text length] > 0 ? [text sizeWithAttributes:nil].height : 0.f; #define AL_MULTILINE_TEXT_HEIGHT(text, font, maxSize, mode) [text length] > 0 ? [text boundingRectWithSize:maxSize \ options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) \ attributes:nil \ context:NULL].size.height : 0.f; #else + #define AL_SINGLELINE_TEXT_HEIGHT(text, font) [text length] > 0 ? [text sizeWithFont:font].height : 0.f; #define AL_MULTILINE_TEXT_HEIGHT(text, font, maxSize, mode) [text length] > 0 ? [text sizeWithFont:font \ constrainedToSize:maxSize \ lineBreakMode:mode].height : 0.f; @@ -420,7 +416,13 @@ -(void)push:(CGFloat)distance forward:(BOOL)forward delay:(double)delay -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - if (self.state == ALAlertBannerStateVisible && self.allowTapToDismiss) + if (self.state != ALAlertBannerStateVisible) + return; + + if (self.tappedBlock) // && !self.isScheduledToHide ...? + self.tappedBlock(self); + + if (self.allowTapToDismiss) [self.delegate hideAlertBanner:self]; } @@ -469,7 +471,7 @@ -(void)setInitialLayout CGSize maxLabelSize = CGSizeMake(parentView.bounds.size.width - (kMargin*3) - self.statusImageView.image.size.width, CGFLOAT_MAX); CGFloat titleLabelHeight = AL_SINGLELINE_TEXT_HEIGHT(self.titleLabel.text, self.titleLabel.font); CGFloat subtitleLabelHeight = AL_MULTILINE_TEXT_HEIGHT(self.subtitleLabel.text, self.subtitleLabel.font, maxLabelSize, self.subtitleLabel.lineBreakMode); - CGFloat heightForSelf = titleLabelHeight + subtitleLabelHeight + (self.subtitleLabel.text == nil ? kMargin*2 : kMargin*2.5); + CGFloat heightForSelf = titleLabelHeight + subtitleLabelHeight + (self.subtitleLabel.text == nil || self.titleLabel.text == nil ? kMargin*2 : kMargin*2.5); CGRect frame = CGRectMake(0, 0, parentView.bounds.size.width, heightForSelf); CGFloat initialYCoord = 0.f; @@ -509,7 +511,7 @@ -(void)updateSizeAndSubviewsAnimated:(BOOL)animated CGSize maxLabelSize = CGSizeMake(self.parentView.bounds.size.width - (kMargin*3) - self.statusImageView.image.size.width, CGFLOAT_MAX); CGFloat titleLabelHeight = AL_SINGLELINE_TEXT_HEIGHT(self.titleLabel.text, self.titleLabel.font); CGFloat subtitleLabelHeight = AL_MULTILINE_TEXT_HEIGHT(self.subtitleLabel.text, self.subtitleLabel.font, maxLabelSize, self.subtitleLabel.lineBreakMode); - CGFloat heightForSelf = titleLabelHeight + subtitleLabelHeight + (self.subtitleLabel.text == nil ? kMargin*2 : kMargin*2.5); + CGFloat heightForSelf = titleLabelHeight + subtitleLabelHeight + (self.subtitleLabel.text == nil || self.titleLabel.text == nil ? kMargin*2 : kMargin*2.5); CFTimeInterval boundsAnimationDuration = AL_DEVICE_ANIMATION_DURATION; @@ -533,9 +535,9 @@ -(void)updateSizeAndSubviewsAnimated:(BOOL)animated [UIView setAnimationDuration:boundsAnimationDuration]; } - self.statusImageView.frame = CGRectMake(kMargin, (self.frame.size.height/2) - (self.statusImageView.image.size.height/2), self.statusImageView.image.size.width, self.statusImageView.image.size.height); + self.statusImageView.frame = CGRectMake(kMargin, (self.frame.size.height/2) - (self.statusImageView.image.size.height/2), self.statusImageView.image.size.width, self.statusImageView.image.size.height); self.titleLabel.frame = CGRectMake(self.statusImageView.frame.origin.x + self.statusImageView.frame.size.width + kMargin, kMargin, maxLabelSize.width, titleLabelHeight); - self.subtitleLabel.frame = CGRectMake(self.titleLabel.frame.origin.x, self.titleLabel.frame.origin.y + self.titleLabel.frame.size.height + kMargin/2, maxLabelSize.width, subtitleLabelHeight); + self.subtitleLabel.frame = CGRectMake(self.titleLabel.frame.origin.x, self.titleLabel.frame.origin.y + self.titleLabel.frame.size.height + (self.titleLabel.text == nil ? 0.f : kMargin/2), maxLabelSize.width, subtitleLabelHeight); if (animated) [UIView commitAnimations]; diff --git a/ALAlertBannerDemo/ALAlertBannerDemo/ViewController.m b/ALAlertBannerDemo/ALAlertBannerDemo/ViewController.m index 89d52a9..f16f8b5 100644 --- a/ALAlertBannerDemo/ALAlertBannerDemo/ViewController.m +++ b/ALAlertBannerDemo/ALAlertBannerDemo/ViewController.m @@ -120,7 +120,12 @@ -(void)showAlertBannerInView:(UIButton*)button { ALAlertBannerPosition position = (ALAlertBannerPosition)button.tag; ALAlertBannerStyle randomStyle = (ALAlertBannerStyle)(arc4random_uniform(4)); - [[ALAlertBannerManager sharedManager] showAlertBannerInView:self.view style:randomStyle position:position title:@"Lorem ipsum dolor sit amet, consectetur adipiscing elit." subtitle:[self randomLoremIpsum]]; + [[ALAlertBannerManager sharedManager] showAlertBannerInView:self.view style:randomStyle position:position title:@"Lorem ipsum dolor sit amet, consectetur adipiscing elit." subtitle:[self randomLoremIpsum] tappedHandler:^(ALAlertBannerView *alertBanner) { + + NSLog(@"tapped!"); + [[ALAlertBannerManager sharedManager] hideAlertBanner:alertBanner]; + + }]; } -(void)showAlertBannerInWindow:(UIButton*)button