diff --git a/ExampleProject/Example/TSDemoViewController.m b/ExampleProject/Example/TSDemoViewController.m index 3f30ef05..f11a058d 100644 --- a/ExampleProject/Example/TSDemoViewController.m +++ b/ExampleProject/Example/TSDemoViewController.m @@ -65,7 +65,8 @@ - (IBAction)didTapButton:(id)sender type:TSMessageNotificationTypeSuccess]; } atPosition:TSMessageNotificationPositionTop - canBeDismissedByUser:YES]; + canBeDismissedByUser:YES + textAlign:NSTextAlignmentCenter]; } - (IBAction)didTapToggleNavigationBar:(id)sender { @@ -92,7 +93,8 @@ - (IBAction)didTapCustomImage:(id)sender buttonTitle:nil buttonCallback:nil atPosition:TSMessageNotificationPositionTop - canBeDismissedByUser:YES]; + canBeDismissedByUser:YES + textAlign:NSTextAlignmentCenter]; } - (IBAction)didTapDismissCurrentMessage:(id)sender @@ -112,7 +114,8 @@ - (IBAction)didTapEndless:(id)sender buttonTitle:nil buttonCallback:nil atPosition:TSMessageNotificationPositionTop - canBeDismissedByUser:NO]; + canBeDismissedByUser:NO + textAlign:NSTextAlignmentCenter]; } - (IBAction)didTapLong:(id)sender @@ -127,7 +130,8 @@ - (IBAction)didTapLong:(id)sender buttonTitle:nil buttonCallback:nil atPosition:TSMessageNotificationPositionTop - canBeDismissedByUser:YES]; + canBeDismissedByUser:YES + textAlign:NSTextAlignmentCenter]; } - (IBAction)didTapBottom:(id)sender @@ -142,7 +146,8 @@ - (IBAction)didTapBottom:(id)sender buttonTitle:nil buttonCallback:nil atPosition:TSMessageNotificationPositionBottom - canBeDismissedByUser:YES]; + canBeDismissedByUser:YES + textAlign:NSTextAlignmentCenter]; } - (IBAction)didTapText:(id)sender diff --git a/README.md b/README.md index befd2dd7..4b90593b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ TSMessages ========== +**Edited** by [Ricardo Pereira](http://twitter.com/ricardopereiraw) +* Add text align support + +-------- + +**Original** + This framework provides an easy to use class to show little notification views on the top of the screen. (à la Tweetbot). The notification moves from the top of the screen underneath the navigation bar and stays there for a few seconds, depending on the length of the displayed text. To dismiss a notification before the time runs out, the user can swipe it to the top or just tap it. @@ -110,4 +117,4 @@ Changes TODOs ----- -Currently empty \ No newline at end of file +* iOS 7: Blur effect diff --git a/TSMessages/Classes/TSMessage.h b/TSMessages/Classes/TSMessage.h index 4156f5d0..e1d28135 100755 --- a/TSMessages/Classes/TSMessage.h +++ b/TSMessages/Classes/TSMessage.h @@ -37,6 +37,7 @@ typedef NS_ENUM(NSInteger, TSMessageNotificationType) { TSMessageNotificationTypeError, TSMessageNotificationTypeSuccess }; + typedef NS_ENUM(NSInteger, TSMessageNotificationPosition) { TSMessageNotificationPositionTop = 0, TSMessageNotificationPositionBottom @@ -95,6 +96,7 @@ typedef NS_ENUM(NSInteger,TSMessageNotificationDuration) { @param buttonCallback The block that should be executed, when the user tapped on the button @param messagePosition The position of the message on the screen @param dismissingEnabled Should the message be dismissed when the user taps/swipes it + @param messageAlign The alignment of the message on the screen */ + (void)showNotificationInViewController:(UIViewController *)viewController title:(NSString *)title @@ -106,7 +108,9 @@ typedef NS_ENUM(NSInteger,TSMessageNotificationDuration) { buttonTitle:(NSString *)buttonTitle buttonCallback:(void (^)())buttonCallback atPosition:(TSMessageNotificationPosition)messagePosition - canBeDismissedByUser:(BOOL)dismissingEnabled; + canBeDismissedByUser:(BOOL)dismissingEnabled + textAlign:(NSTextAlignment)messageAlign; + /** Fades out the currently displayed notification. If another notification is in the queue, the next one will be displayed automatically diff --git a/TSMessages/Classes/TSMessage.m b/TSMessages/Classes/TSMessage.m index 5fbb149e..7f4d5a38 100755 --- a/TSMessages/Classes/TSMessage.m +++ b/TSMessages/Classes/TSMessage.m @@ -80,7 +80,8 @@ + (void)showNotificationInViewController:(UIViewController *)viewController buttonTitle:nil buttonCallback:nil atPosition:TSMessageNotificationPositionTop - canBeDismissedByUser:YES]; + canBeDismissedByUser:YES + textAlign:NSTextAlignmentLeft]; } @@ -95,6 +96,7 @@ + (void)showNotificationInViewController:(UIViewController *)viewController buttonCallback:(void (^)())buttonCallback atPosition:(TSMessageNotificationPosition)messagePosition canBeDismissedByUser:(BOOL)dismissingEnabled + textAlign:(NSTextAlignment)messageAlign { // Create the TSMessageView TSMessageView *v = [[TSMessageView alloc] initWithTitle:title @@ -107,7 +109,8 @@ + (void)showNotificationInViewController:(UIViewController *)viewController buttonTitle:buttonTitle buttonCallback:buttonCallback atPosition:messagePosition - canBeDismissedByUser:dismissingEnabled]; + canBeDismissedByUser:dismissingEnabled + textAlign:messageAlign]; [self prepareNotificationToBeShown:v]; } @@ -170,7 +173,7 @@ - (void)fadeInCurrentNotification currentNavigationController = (UINavigationController *)currentView.viewController; else currentNavigationController = (UINavigationController *)currentView.viewController.parentViewController; - + BOOL isViewIsUnderStatusBar = [[[currentNavigationController childViewControllers] firstObject] wantsFullScreenLayout]; if (!isViewIsUnderStatusBar && currentNavigationController.parentViewController == nil) { isViewIsUnderStatusBar = ![currentNavigationController isNavigationBarHidden]; // strange but true @@ -179,7 +182,14 @@ - (void)fadeInCurrentNotification { [currentNavigationController.view insertSubview:currentView belowSubview:[currentNavigationController navigationBar]]; - verticalOffset = [currentNavigationController navigationBar].bounds.size.height; + + NSArray *titleViewsBounds = [currentView.viewController.navigationController.viewControllers valueForKeyPath:@"navigationItem.titleView.bounds"]; + __block CGFloat maxTitleViewHeight = 0.0; + [titleViewsBounds enumerateObjectsUsingBlock:^(NSValue *boundsValue, NSUInteger idx, BOOL *stop) { + CGRect rect = [boundsValue isEqual:NSNull.null] ? CGRectZero : boundsValue.CGRectValue; + maxTitleViewHeight = CGRectGetHeight(rect) > maxTitleViewHeight ? CGRectGetHeight(rect) : maxTitleViewHeight; + }]; + verticalOffset = MAX([currentNavigationController navigationBar].bounds.size.height, maxTitleViewHeight); if ([TSMessage iOS7StyleEnabled] || isViewIsUnderStatusBar) { addStatusBarHeightToVerticalOffset(); } @@ -219,7 +229,7 @@ - (void)fadeInCurrentNotification } toPoint = CGPointMake(currentView.center.x, y); } - + dispatch_block_t animationBlock = ^{ currentView.center = toPoint; if (![TSMessage iOS7StyleEnabled]) { @@ -361,7 +371,7 @@ + (BOOL)iOS7StyleEnabled // Decide wheter to use iOS 7 style or not based on the running device and the base sdk BOOL iOS7SDK = NO; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 - iOS7SDK = YES; + iOS7SDK = YES; #endif _useiOS7Style = ! (TS_SYSTEM_VERSION_LESS_THAN(@"7.0") || !iOS7SDK); diff --git a/TSMessages/Views/TSMessageView.h b/TSMessages/Views/TSMessageView.h index b52cf221..a40b52bc 100755 --- a/TSMessages/Views/TSMessageView.h +++ b/TSMessages/Views/TSMessageView.h @@ -39,6 +39,9 @@ /** The position of the message (top or bottom) */ @property (nonatomic, assign) TSMessageNotificationPosition messagePosition; +/** The alignment of the message (left, center, right, justified, natural) */ +@property (nonatomic, assign) NSTextAlignment messageAlignment; + /** Is the message currenlty fully displayed? Is set as soon as the message is really fully visible */ @property (nonatomic, assign) BOOL messageIsFullyDisplayed; @@ -57,6 +60,7 @@ @param buttonCallback The block that should be executed, when the user tapped on the button @param position The position of the message on the screen @param dismissingEnabled Should this message be dismissed when the user taps/swipes it? + @param textAlign The align of the message on the screen */ - (id)initWithTitle:(NSString *)title subtitle:(NSString *)subtitle @@ -68,7 +72,9 @@ buttonTitle:(NSString *)buttonTitle buttonCallback:(void (^)())buttonCallback atPosition:(TSMessageNotificationPosition)position -canBeDismissedByUser:(BOOL)dismissingEnabled; +canBeDismissedByUser:(BOOL)dismissingEnabled + textAlign:(NSTextAlignment)alignment; + /** Fades out this notification view */ - (void)fadeMeOut; diff --git a/TSMessages/Views/TSMessageView.m b/TSMessages/Views/TSMessageView.m index 00177ed0..90c68347 100755 --- a/TSMessages/Views/TSMessageView.m +++ b/TSMessages/Views/TSMessageView.m @@ -7,8 +7,7 @@ // #import "TSMessageView.h" -#import "HexColor.h" -#import "TSBlurView.h" +#import "HexColors.h" #import "TSMessage.h" @@ -45,7 +44,7 @@ @interface TSMessageView () @property (nonatomic, strong) UIButton *button; @property (nonatomic, strong) UIView *borderView; @property (nonatomic, strong) UIImageView *backgroundImageView; -@property (nonatomic, strong) TSBlurView *backgroundBlurView; // Only used in iOS 7 +@property (nonatomic, strong) UIView *backgroundView; // Only used in iOS 7 @property (nonatomic, assign) CGFloat textSpaceLeft; @property (nonatomic, assign) CGFloat textSpaceRight; @@ -67,8 +66,8 @@ + (NSMutableDictionary *)notificationDesign { NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:TSDesignFileName]; _notificationDesign = [NSMutableDictionary dictionaryWithDictionary:[NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:path] - options:kNilOptions - error:nil]]; + options:kNilOptions + error:nil]]; } return _notificationDesign; @@ -79,8 +78,8 @@ + (void)addNotificationDesignFromFile:(NSString *)filename { NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:filename]; NSDictionary *design = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:path] - options:kNilOptions - error:nil]; + options:kNilOptions + error:nil]; [[TSMessageView notificationDesign] addEntriesFromDictionary:design]; } @@ -96,6 +95,7 @@ - (id)initWithTitle:(NSString *)title buttonCallback:(void (^)())buttonCallback atPosition:(TSMessageNotificationPosition)position canBeDismissedByUser:(BOOL)dismissingEnabled + textAlign:(NSTextAlignment)alignment { NSDictionary *notificationDesign = [TSMessageView notificationDesign]; @@ -107,6 +107,7 @@ - (id)initWithTitle:(NSString *)title _duration = duration; _viewController = viewController; _messagePosition = position; + _messageAlignment = alignment; self.callback = callback; self.buttonCallback = buttonCallback; @@ -141,7 +142,7 @@ - (id)initWithTitle:(NSString *)title } current = [notificationDesign valueForKey:currentString]; - + if (!image && [current valueForKey:@"imageName"]) { @@ -160,11 +161,10 @@ - (id)initWithTitle:(NSString *)title } else { - // On iOS 7 and above use a blur layer instead (not yet finished) - _backgroundBlurView = [[TSBlurView alloc] init]; - self.backgroundBlurView.autoresizingMask = (UIViewAutoresizingFlexibleWidth); - self.backgroundBlurView.blurTintColor = [UIColor colorWithHexString:current[@"backgroundColor"]]; - [self addSubview:self.backgroundBlurView]; + _backgroundView = [[UIView alloc] init]; + self.backgroundView.autoresizingMask = (UIViewAutoresizingFlexibleWidth); + self.backgroundView.backgroundColor = [UIColor colorWithHexString:current[@"backgroundColor"] alpha:current[@"backgroundAlpha"] ? [current[@"backgroundAlpha"] floatValue] : 1.0]; + [self addSubview:self.backgroundView]; } UIColor *fontColor = [UIColor colorWithHexString:[current valueForKey:@"textColor"] @@ -191,6 +191,13 @@ - (id)initWithTitle:(NSString *)title [[current valueForKey:@"shadowOffsetY"] floatValue])]; self.titleLabel.numberOfLines = 0; self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; + // Check alignment: layout has priority! + int align = [[current valueForKey:@"textAlignment"] intValue]; + if (align > 0) + self.titleLabel.textAlignment = align; + else + self.titleLabel.textAlignment = self.messageAlignment; + [self addSubview:self.titleLabel]; // Set up content label (if set) @@ -217,7 +224,12 @@ - (id)initWithTitle:(NSString *)title [self.contentLabel setShadowOffset:self.titleLabel.shadowOffset]; self.contentLabel.lineBreakMode = self.titleLabel.lineBreakMode; self.contentLabel.numberOfLines = 0; - + // Check alignment: layout has priority! + if (align > 0) + self.contentLabel.textAlignment = align; + else + self.contentLabel.textAlignment = self.messageAlignment; + [self addSubview:self.contentLabel]; } @@ -347,6 +359,11 @@ - (CGFloat)updateHeightOfMessageView 0.0); [self.titleLabel sizeToFit]; + // for title text alignment + CGRect currFrame = self.titleLabel.frame; + + self.titleLabel.frame = CGRectMake(currFrame.origin.x, currFrame.origin.y, screenWidth - TSMessageViewPadding - self.iconImageView.frame.origin.x - self.iconImageView.frame.size.width - TSMessageViewPadding - self.textSpaceLeft - self.textSpaceRight, currFrame.size.height); + if ([self.subtitle length]) { self.contentLabel.frame = CGRectMake(self.textSpaceLeft, @@ -355,6 +372,11 @@ - (CGFloat)updateHeightOfMessageView 0.0); [self.contentLabel sizeToFit]; + // for content text alignment + currFrame = self.contentLabel.frame; + + self.contentLabel.frame = CGRectMake(currFrame.origin.x, currFrame.origin.y, screenWidth - TSMessageViewPadding - self.iconImageView.frame.origin.x - self.iconImageView.frame.size.width - TSMessageViewPadding - self.textSpaceLeft - self.textSpaceRight, currFrame.size.height); + currentHeight = self.contentLabel.frame.origin.y + self.contentLabel.frame.size.height; } else @@ -404,20 +426,34 @@ - (CGFloat)updateHeightOfMessageView self.button.frame.size.width, self.button.frame.size.height); } + + + NSArray *titleViewsBounds = [self.viewController.navigationController.viewControllers valueForKeyPath:@"navigationItem.titleView.bounds"]; + __block CGFloat maxTitleViewHeight = 0.0; + CGFloat differenceHeight = 0.0; + [titleViewsBounds enumerateObjectsUsingBlock:^(NSValue *boundsValue, NSUInteger idx, BOOL *stop) { + CGRect rect = [boundsValue isEqual:NSNull.null] ? CGRectZero : boundsValue.CGRectValue; + maxTitleViewHeight = CGRectGetHeight(rect) > maxTitleViewHeight ? CGRectGetHeight(rect) : maxTitleViewHeight; + }]; - + if (maxTitleViewHeight > currentHeight) + { + differenceHeight = maxTitleViewHeight - currentHeight; + currentHeight += differenceHeight; + } + CGRect backgroundFrame = CGRectMake(self.backgroundImageView.frame.origin.x, - self.backgroundImageView.frame.origin.y, + MIN(self.backgroundImageView.frame.origin.y, -differenceHeight), screenWidth, currentHeight); - + // increase frame of background view because of the spring animation if ([TSMessage iOS7StyleEnabled]) { if (self.messagePosition == TSMessageNotificationPositionTop) { float topOffset = 0.f; - + UINavigationController *navigationController = self.viewController.navigationController; if (!navigationController && [self.viewController isKindOfClass:[UINavigationController class]]) { navigationController = (UINavigationController *)self.viewController; @@ -435,9 +471,9 @@ - (CGFloat)updateHeightOfMessageView backgroundFrame = UIEdgeInsetsInsetRect(backgroundFrame, UIEdgeInsetsMake(0.f, 0.f, -30.f, 0.f)); } } - + self.backgroundImageView.frame = backgroundFrame; - self.backgroundBlurView.frame = backgroundFrame; + self.backgroundView.frame = backgroundFrame; return currentHeight; }