├── .gitignore ├── LICENSE ├── MessageBanner.podspec ├── MessageBanner ├── Classes │ ├── MBLMessageBanner.h │ └── MBLMessageBanner.m ├── LICENSE ├── Ressources │ ├── Configuration Files │ │ └── MessageBannerDesign.json │ └── Images │ │ ├── ErrorBackgroundDefaultImage.png │ │ ├── ErrorBackgroundDefaultImage@2x.png │ │ ├── ErrorDefaultLeftImage.png │ │ ├── ErrorDefaultLeftImage@2x.png │ │ ├── MessageBackgroundDefaultImage.png │ │ ├── MessageBackgroundDefaultImage@2x.png │ │ ├── MessageDefaultLeftImage.png │ │ ├── MessageDefaultLeftImage@2x.png │ │ ├── SuccessBackgroundDefaultImage.png │ │ ├── SuccessBackgroundDefaultImage@2x.png │ │ ├── SuccessDefaultLeftImage.png │ │ ├── SuccessDefaultLeftImage@2x.png │ │ ├── WarningBackgroundDefaultImage.png │ │ ├── WarningBackgroundDefaultImage@2x.png │ │ ├── WarningDefaultLeftImage.png │ │ └── WarningDefaultLeftImage@2x.png └── Views │ ├── MBLMessageBannerView.h │ └── MBLMessageBannerView.m ├── MessageBannerDemo ├── .gitignore ├── MessageBannerDemo.xcodeproj │ └── project.pbxproj ├── MessageBannerDemo │ ├── Base.lproj │ │ └── Main.storyboard │ ├── CustomBannerDesign.json │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── MBDAppDelegate.h │ ├── MBDAppDelegate.m │ ├── MBDViewController.h │ ├── MBDViewController.m │ ├── MessageBannerDemo-Info.plist │ ├── MessageBannerDemo-Prefix.pch │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m └── Podfile ├── README.md └── Screenshots ├── ErrorMessageBanner.png ├── MessageBannerBottomPosition.png ├── MessageBannerErrorType.png ├── MessageBannerMessageType.png ├── MessageBannerMiddlePosition.png ├── MessageBannerSuccessType.png ├── MessageBannerTopPosition.png ├── MessageBannerWarningType.png ├── MessageMessageBanner.png ├── SuccessMessageBanner.png ├── WarningMessageBanner.png └── liveDemo.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # CocoaPods 2 | # 3 | # We recommend against adding the Pods directory to your .gitignore. However 4 | # you should judge for yourself, the pros and cons are mentioned at: 5 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 6 | # 7 | # Pods/ 8 | 9 | # Xcode 10 | .DS_Store 11 | build/ 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | *.xcworkspace 21 | !default.xcworkspace 22 | xcuserdata 23 | profile 24 | *.moved-aside 25 | DerivedData 26 | .idea/ 27 | # Pods - for those of you who use CocoaPods 28 | Pods -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Thibault Carpentier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /MessageBanner.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint MessageBanner.podspec' to ensure this is a 3 | # valid spec and remove all comments before submitting the spec. 4 | # 5 | # Any lines starting with a # are optional, but encouraged 6 | # 7 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 8 | # 9 | 10 | Pod::Spec.new do |s| 11 | s.name = "MessageBanner" 12 | s.version = "1.0.4" 13 | s.summary = "iOS Notification / Message easy to use and fully customisable" 14 | s.description = <<-DESC 15 | 16 | This library provides an **easy to use and fully customizable class to show notifications** views on top/bottom/center of the screen. 17 | 18 | The messages banners are regrouped in 4 different type : **Error**, **Warning**, **Message** and **Success**. 19 | 20 | Each different type of banner can have different and fully customizable appearance and behavior. (See configuration section) 21 | 22 | Each banner can show a **title**, a **subtitle**, an **image** and a **button**. 23 | 24 | DESC 25 | s.homepage = "https://github.com/Loadex/MessageBanner" 26 | s.screenshots = "https://raw.githubusercontent.com/Loadex/MessageBanner/master/Screenshots/MessageBannerErrorType.png", "https://raw.githubusercontent.com/Loadex/MessageBanner/master/Screenshots/MessageBannerWarningType.png" , "https://raw.githubusercontent.com/Loadex/MessageBanner/master/Screenshots/MessageBannerMessageType.png" , "https://raw.githubusercontent.com/Loadex/MessageBanner/master/Screenshots/MessageBannerSuccessType.png" 27 | 28 | s.license = 'MIT' 29 | s.author = { "Thibault Carpentier" => "carpen_t@epitech.eu" } 30 | s.source = { :git => "https://github.com/Loadex/MessageBanner.git", :tag => s.version.to_s } 31 | # s.social_media_url = 'https://twitter.com/' 32 | 33 | s.platform = :ios, '7.0' 34 | s.requires_arc = true 35 | 36 | s.source_files = 'MessageBanner/Classes/**/*.{h,m}', 'MessageBanner/Views/**/*.{h,m}' 37 | s.resources = 'MessageBanner/Ressources/**/*.{png,json}' 38 | 39 | s.public_header_files = 'MessageBanner/Classes/**/*.{h}', 'MessageBanner/Views/**/*.{h}' 40 | # s.frameworks = 'UIKit', 'MapKit' 41 | s.dependency 'HexColors', '~> 2.3.0' 42 | s.dependency 'FXBlurView', '~> 1.6.1' 43 | end 44 | -------------------------------------------------------------------------------- /MessageBanner/Classes/MBLMessageBanner.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MBLMessageBanner.h 3 | * @Author Thibault Carpentier 4 | * @date 2014 5 | * @brief MBLMessageBannerView manager. 6 | * 7 | * MBLMessageBanner allow to easilly manage popups. 8 | */ 9 | 10 | 11 | #import 12 | 13 | /** 14 | Message banner notification sended when the messagebanner will appear 15 | */ 16 | #define MESSAGE_BANNER_VIEW_WILL_APPEAR_NOTIFICATION @"MBLMessageBannerViewWillAppearNotification" 17 | /** 18 | Message banner notification sended when the messagebanner did appear 19 | */ 20 | #define MESSAGE_BANNER_VIEW_DID_APPEAR_NOTIFICATION @"MBLMessageBannerViewDidAppearNotification" 21 | /** 22 | Message banner notification sended when the messagebanner will disappear 23 | */ 24 | #define MESSAGE_BANNER_VIEW_WILL_DISAPPEAR_NOTIFICATION @"MBLMessageBannerViewWillDisappearNotification" 25 | /** 26 | Message banner notification sended when the messagebanner did disappear 27 | */ 28 | #define MESSAGE_BANNER_VIEW_DID_DISAPPEAR_NOTIFICATION @"MBLMessageBannerViewDidDisappearNotification" 29 | 30 | 31 | // Forward declaration to avoid double includes problems 32 | @class MBLMessageBannerView; 33 | 34 | /** 35 | An enumeration of MBLMessageBannerView types 36 | */ 37 | typedef NS_ENUM(NSInteger, MBLMessageBannerType) { 38 | MBLMessageBannerTypeError = 0 /** A message banner used to show errors */ 39 | , MBLMessageBannerTypeWarning = 1 /** A message banner used to show warnings */ 40 | , MBLMessageBannerTypeMessage = 2 /** A message banner used to show message */ 41 | , MBLMessageBannerTypeSuccess = 3 /** A message banner used to show success */ 42 | }; 43 | /** 44 | An enumeration of MBLMessageBannerView positions 45 | */ 46 | typedef NS_ENUM(NSInteger, MBLMessageBannerPosition) { 47 | MBLMessageBannerPositionTop = 0 /** A top positioned message banner */ 48 | , MBLMessageBannerPositionCenter = 1 /** A centered positioned message banner */ 49 | , MBLMessageBannerPositionBottom = 2 /** A bottom positioned message banner */ 50 | }; 51 | /** 52 | An enumeration of custom message banner duration 53 | */ 54 | typedef NS_ENUM(NSInteger, MBLMessageBannerDuration) { 55 | MBLMessageBannerDurationDefault = 0 /** A duration calculated automatically */ 56 | , MBLMessageBannerDurationEndless = -1 /** An endless duration */ 57 | }; 58 | 59 | 60 | /** 61 | Set of methods to implement to be notified on appearance/disappearance of message banners 62 | */ 63 | @protocol MBLMessageBannerDelegate 64 | @optional 65 | /** 66 | A message Banner view will appear 67 | @param MessageBanner the message banner about to appear 68 | */ 69 | - (void)messageBannerViewWillAppear:(MBLMessageBannerView *)messageBanner; 70 | /** 71 | A message Banner view did appear 72 | @param MessageBanner the message banner which appeared 73 | */ 74 | - (void)messageBannerViewDidAppear:(MBLMessageBannerView *)messageBanner; 75 | /** 76 | A message Banner view will disappear 77 | @param messageBanner the message banner about to disappear 78 | */ 79 | - (void)messageBannerViewWillDisappear:(MBLMessageBannerView *)messageBanner; 80 | /** 81 | A message Banner view did disappear 82 | @param messageBanner the message banner which disappeared 83 | */ 84 | - (void)messageBannerViewDidDisappear:(MBLMessageBannerView *)messageBanner; 85 | @end 86 | 87 | 88 | /** 89 | A message banner manager class 90 | */ 91 | @interface MBLMessageBanner : NSObject 92 | 93 | /** 94 | Returns the shared instance of the manager 95 | @returns manager shared instance 96 | */ 97 | + (instancetype) sharedSingleton; 98 | /** 99 | Return the defaultViewController 100 | @return The default view controller 101 | */ 102 | + (UIViewController *)defaultViewController; 103 | /** 104 | Set the default view controller 105 | @param aViewController the new default view controller 106 | */ 107 | + (void)setDefaultViewController:(UIViewController *)aViewController; 108 | #pragma mark - Set Delegate 109 | 110 | /** 111 | Set MessageBanner delegate 112 | @param aDelegate the new message banner Delegate 113 | */ 114 | + (void)setMessageBannerDelegate:(id)aDelegate; 115 | 116 | #pragma mark - Show Methods 117 | 118 | /** 119 | Show a message banner 120 | @param messageView The message banner view to show 121 | @param viewController The view where the message banner will be added 122 | */ 123 | + (void)showMessageBanner:(MBLMessageBannerView*)messageView; 124 | 125 | /** 126 | Show a message banner 127 | @param viewController The view where the message banner will be added 128 | @param title The title of the message banner 129 | @param subtitle The subtitle of the message banner 130 | */ 131 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 132 | title:(NSString *)title 133 | subtitle:(NSString *)subtitle; 134 | /** 135 | Show a message banner 136 | @param viewController The view where the message banner will be added 137 | @param title The title of the message banner 138 | @param subtitle The subtitle of the message banner 139 | @param messagePosition The position of the message banner @see MessageBannerPosition values 140 | */ 141 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 142 | title:(NSString *)title 143 | subtitle:(NSString *)subtitle 144 | atPosition:(MBLMessageBannerPosition)messagePosition; 145 | /** 146 | Show a message banner 147 | @param viewController The view where the message banner will be added 148 | @param title The title of the message banner 149 | @param subtitle The subtitle of the message banner 150 | @param type The type of the message banner @see MessageBannerType values 151 | @param messagePosition The position of the message banner @see MessageBannerPosition values 152 | */ 153 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 154 | title:(NSString *)title 155 | subtitle:(NSString *)subtitle 156 | type:(MBLMessageBannerType)type 157 | atPosition:(MBLMessageBannerPosition)messagePosition; 158 | /** 159 | Show a message banner 160 | @param viewController The view where the message banner will be added 161 | @param title The title of the message banner 162 | @param subtitle The subtitle of the message banner 163 | @param type The type of the message banner @see MBLMessageBannerType values 164 | @param duration The popup duration on screen @see MBLMessageBannerDuration for specials durations 165 | @param messagePosition The position of the message banner @see MBLMessageBannerPosition values 166 | */ 167 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 168 | title:(NSString *)title 169 | subtitle:(NSString *)subtitle 170 | type:(MBLMessageBannerType)type 171 | duration:(NSTimeInterval)duration 172 | atPosition:(MBLMessageBannerPosition)messagePosition; 173 | /** 174 | Show a message banner 175 | @param viewController The view where the message banner will be added 176 | @param title The title of the message banner 177 | @param subtitle The subtitle of the message banner 178 | @param type The type of the message banner @see MBLMessageBannerType values 179 | @param duration The popup duration on screen @see MBLMessageBannerDuration for specials durations 180 | @param userDissmissedCallback A callback when the user dismiss the popup 181 | @param messagePosition The position of the message banner @see MBLMessageBannerPosition values 182 | @param dismissingEnabled Enable/Disable user dismiss on the message banner 183 | */ 184 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 185 | title:(NSString *)title 186 | subtitle:(NSString *)subtitle 187 | type:(MBLMessageBannerType)type 188 | duration:(NSTimeInterval)duration 189 | userDissmissedCallback:(void (^)(MBLMessageBannerView* bannerView))userDissmissedCallback 190 | atPosition:(MBLMessageBannerPosition)messagePosition 191 | canBeDismissedByUser:(BOOL)dismissingEnabled; 192 | /** 193 | Show a message banner 194 | @param viewController The view where the message banner will be added 195 | @param title The title of the message banner 196 | @param subtitle The subtitle of the message banner 197 | @param image The image to show on the left of the message banner 198 | @param type The type of the message banner @see MBLMessageBannerType values 199 | @param duration The popup duration on screen @see MBLMessageBannerDuration for specials durations 200 | @param userDissmissedCallback A callback when the user dismiss the popup 201 | @param messagePosition The position of the message banner @see MBLMessageBannerPosition values 202 | @param dismissingEnabled Enable/Disable user dismiss on the message banner 203 | */ 204 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 205 | title:(NSString *)title 206 | subtitle:(NSString *)subtitle 207 | image:(UIImage *)image 208 | type:(MBLMessageBannerType)type 209 | duration:(NSTimeInterval)duration 210 | userDissmissedCallback:(void (^)(MBLMessageBannerView* bannerView))userDissmissedCallback 211 | atPosition:(MBLMessageBannerPosition)messagePosition 212 | canBeDismissedByUser:(BOOL)dismissingEnabled; 213 | /** 214 | Show a message banner 215 | @param viewController The view where the message banner will be added 216 | @param title The title of the message banner 217 | @param subtitle The subtitle of the message banner 218 | @param image The image to show on the left of the message banner 219 | @param type The type of the message banner @see MBLMessageBannerType values 220 | @param duration The popup duration on screen @see MBLMessageBannerDuration for specials durations 221 | @param userDissmissedCallback A callback when the user dismiss the popup 222 | @param buttonTitle Enable a button on the right of the view created with this title 223 | @param userPressedButtonCallback A callback when the user press the button 224 | @param messagePosition The position of the message banner @see MBLMessageBannerPosition values 225 | @param dismissingEnabled Enable/Disable user dismiss on the message banner 226 | @param aDelegate Set the class delegate if not setted yet 227 | */ 228 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 229 | title:(NSString *)title 230 | subtitle:(NSString *)subtitle 231 | image:(UIImage *)image 232 | type:(MBLMessageBannerType)type 233 | duration:(NSTimeInterval)duration 234 | userDissmissedCallback:(void (^)(MBLMessageBannerView* bannerView))userDissmissedCallback 235 | buttonTitle:(NSString *)buttonTitle 236 | userPressedButtonCallback:(void (^)(MBLMessageBannerView* banner))userPressedButtonCallback 237 | atPosition:(MBLMessageBannerPosition)messagePosition 238 | canBeDismissedByUser:(BOOL)dismissingEnabled 239 | delegate:(id )aDelegate; 240 | 241 | #pragma mark - Hide Methods 242 | /** 243 | Hide the current message banner on screen 244 | @returns the success of the operation 245 | @retval NO If there is no message banner to hide 246 | @retval YES If a message banner has been hiden 247 | */ 248 | + (BOOL) hideMessageBanner; 249 | /** 250 | Hide the current message banner on screen 251 | @param completion A callback when the message banner is hidden 252 | @returns the success of the operation 253 | @retval NO if there is no message banner to hide 254 | @retval YES if a message banner has been hiden 255 | */ 256 | + (BOOL) hideMessageBannerWithCompletion:(void (^)())completion; 257 | 258 | @end 259 | -------------------------------------------------------------------------------- /MessageBanner/Classes/MBLMessageBanner.m: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MBLMessageBanner.m 3 | * @Author Thibault Carpentier 4 | * @date 2014 5 | * @brief MBLMessageBannerView manager. 6 | * 7 | * MBLMessageBanner allow to easilly manage popups. 8 | */ 9 | 10 | #import "MBLMessageBanner.h" 11 | #import "MBLMessageBannerView.h" 12 | 13 | #pragma mark - MBLMessageBanner interface 14 | @interface MBLMessageBanner () 15 | /** 16 | Determine if a message is on the screen or not 17 | */ 18 | @property (nonatomic, assign) BOOL messageOnScreen; 19 | /** 20 | The list of message to be shown 21 | */ 22 | @property (nonatomic, strong) NSMutableArray *messagesBannersList; 23 | @end 24 | 25 | #pragma mark - MBLMessageBannerView usefull methods 26 | /** 27 | Undocumented private methods calls for internal use 28 | */ 29 | @interface MBLMessageBannerView () 30 | - (void)setBlur; 31 | - (void)unsetBlur; 32 | @end 33 | 34 | @implementation MBLMessageBanner 35 | 36 | 37 | #pragma mark - Default Calculation duration values 38 | /** 39 | Default class animation duration 40 | */ 41 | #define ANIMATION_DURATION 0.5 42 | /** 43 | Default class display time per pixel user in automatic duration calculs 44 | */ 45 | #define DISPLAY_TIME_PER_PIXEL 0.04 46 | /** 47 | Default display duration used in automatic duration calculs 48 | */ 49 | #define DISPLAY_DEFAULT_DURATION 2.0 50 | 51 | 52 | #pragma mark - Default Message Banner configuration 53 | /** 54 | Default banner type 55 | */ 56 | #define TYPE_DEFAULT MBLMessageBannerTypeMessage 57 | /** 58 | Default message banner duration mode 59 | */ 60 | #define DURATION_DEFAULT MBLMessageBannerDurationDefault 61 | /** 62 | Default message banner position mode 63 | */ 64 | #define POSITION_DEFAULT MBLMessageBannerPositionTop 65 | /** 66 | Default user dismiss message banner mode 67 | */ 68 | #define USER_DISMISS_DEFAULT YES 69 | 70 | #pragma mark - static instances 71 | /** 72 | Singleton instance 73 | */ 74 | static MBLMessageBanner *sharedSingleton; 75 | /** 76 | Default view controller used if viewcontroller is nil or not passed as a parameter 77 | */ 78 | static UIViewController* _defaultViewController; 79 | /** 80 | Class delegate instance 81 | */ 82 | static id _delegate; 83 | /** 84 | Caching delegate methods implementation stucture 85 | */ 86 | static struct delegateMethodsCaching { 87 | 88 | unsigned int messageBannerViewWillAppear:1; 89 | unsigned int messageBannerViewDidAppear:1; 90 | unsigned int messageBannerViewWillDisappear:1; 91 | unsigned int messageBannerViewDidDisappear:1; 92 | 93 | } _delegateRespondTo; 94 | 95 | 96 | #pragma mark - Init and singleton methods 97 | /** 98 | Returns the shared instance of the manager 99 | @returns manager shared instance 100 | */ 101 | + (MBLMessageBanner *)sharedSingleton 102 | { 103 | if (!sharedSingleton) 104 | { 105 | sharedSingleton = [[[self class] alloc] init]; 106 | } 107 | return sharedSingleton; 108 | } 109 | /** 110 | Returns the default view controller 111 | @returns the default view controller where the banner is attached if the viewcontroller parameter is nil 112 | */ 113 | + (UIViewController*)defaultViewController { 114 | __strong UIViewController* defaultViewController = _defaultViewController; 115 | if (!defaultViewController) { 116 | defaultViewController = [UIApplication sharedApplication].keyWindow.rootViewController; 117 | } 118 | return defaultViewController; 119 | } 120 | 121 | - (id)init { 122 | if ((self = [super init])) { 123 | _messagesBannersList = [[NSMutableArray alloc] init]; 124 | _messageOnScreen = NO; 125 | } 126 | return self; 127 | } 128 | 129 | #pragma mark - 130 | #pragma mark Default view controller methods 131 | /** 132 | Set the default view controller 133 | @param aViewController The new controller to set as default 134 | */ 135 | + (void)setDefaultViewController:(UIViewController *)aViewController { 136 | _defaultViewController = aViewController; 137 | } 138 | 139 | #pragma mark - 140 | #pragma mark Delegate Methods 141 | 142 | + (void)setMessageBannerDelegate:(id)aDelegate { 143 | if (_delegate != aDelegate) { 144 | 145 | _delegate = aDelegate; 146 | 147 | struct delegateMethodsCaching newMethodCaching; 148 | 149 | newMethodCaching.messageBannerViewWillAppear = [_delegate respondsToSelector:@selector(messageBannerViewWillAppear:)]; 150 | 151 | newMethodCaching.messageBannerViewDidAppear = [_delegate respondsToSelector:@selector(messageBannerViewDidAppear:)]; 152 | 153 | newMethodCaching.messageBannerViewWillDisappear = [_delegate respondsToSelector:@selector(messageBannerViewWillDisappear:)]; 154 | 155 | newMethodCaching.messageBannerViewDidDisappear = [_delegate respondsToSelector:@selector(messageBannerViewDidDisappear:)]; 156 | 157 | _delegateRespondTo = newMethodCaching; 158 | } 159 | } 160 | 161 | #pragma mark - 162 | #pragma mark Show methods 163 | 164 | + (void)showMessageBanner:(MBLMessageBannerView *)messageBannerView { 165 | 166 | 167 | // Preparing and showing notification Future version protection 168 | //#warning uncomment after testing 169 | 170 | // NSString *title = messageBannerView.title; 171 | // NSString *subtitle = messageBannerView.subTitle; 172 | // for (MBLMessageBannerView *n in [MBLMessageBanner sharedSingleton].messagesBannersList) 173 | // { 174 | // if (([n.title isEqualToString:title] || (!n.title && !title)) && ([n.subTitle isEqualToString:subtitle] || (!n.subTitle && !subtitle))) 175 | // { 176 | // // Add some check in the config file later if it allow multiple pop-ups 177 | // return; 178 | // } 179 | // } 180 | 181 | [[MBLMessageBanner sharedSingleton].messagesBannersList addObject:messageBannerView]; 182 | 183 | if ([[MBLMessageBanner sharedSingleton] messageOnScreen] == NO) { 184 | [[MBLMessageBanner sharedSingleton] showMessageBannerOnScreen]; 185 | } 186 | } 187 | 188 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 189 | title:(NSString *)title 190 | subtitle:(NSString *)subtitle { 191 | [self showMessageBannerInViewController:viewController 192 | title:title 193 | subtitle:subtitle 194 | image:nil 195 | type:TYPE_DEFAULT 196 | duration:DURATION_DEFAULT 197 | userDissmissedCallback:nil 198 | buttonTitle:nil 199 | userPressedButtonCallback:nil 200 | atPosition:POSITION_DEFAULT 201 | canBeDismissedByUser:USER_DISMISS_DEFAULT 202 | delegate:nil]; 203 | } 204 | 205 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 206 | title:(NSString *)title 207 | subtitle:(NSString *)subtitle 208 | atPosition:(MBLMessageBannerPosition)messagePosition { 209 | 210 | [self showMessageBannerInViewController:viewController 211 | title:title 212 | subtitle:subtitle 213 | image:nil 214 | type:TYPE_DEFAULT 215 | duration:DURATION_DEFAULT 216 | userDissmissedCallback:nil 217 | buttonTitle:nil 218 | userPressedButtonCallback:nil 219 | atPosition:messagePosition 220 | canBeDismissedByUser:USER_DISMISS_DEFAULT 221 | delegate:nil]; 222 | } 223 | 224 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 225 | title:(NSString *)title 226 | subtitle:(NSString *)subtitle 227 | type:(MBLMessageBannerType)type 228 | atPosition:(MBLMessageBannerPosition)messagePosition { 229 | 230 | [self showMessageBannerInViewController:viewController 231 | title:title 232 | subtitle:subtitle 233 | image:nil 234 | type:type 235 | duration:DURATION_DEFAULT 236 | userDissmissedCallback:nil 237 | buttonTitle:nil 238 | userPressedButtonCallback:nil 239 | atPosition:messagePosition 240 | canBeDismissedByUser:USER_DISMISS_DEFAULT 241 | delegate:nil]; 242 | } 243 | 244 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 245 | title:(NSString *)title 246 | subtitle:(NSString *)subtitle 247 | type:(MBLMessageBannerType)type 248 | duration:(NSTimeInterval)duration 249 | atPosition:(MBLMessageBannerPosition)messagePosition { 250 | 251 | [self showMessageBannerInViewController:viewController 252 | title:title 253 | subtitle:subtitle 254 | image:nil 255 | type:type 256 | duration:duration 257 | userDissmissedCallback:nil 258 | buttonTitle:nil 259 | userPressedButtonCallback:nil 260 | atPosition:messagePosition 261 | canBeDismissedByUser:USER_DISMISS_DEFAULT 262 | delegate:nil]; 263 | } 264 | 265 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 266 | title:(NSString *)title 267 | subtitle:(NSString *)subtitle 268 | type:(MBLMessageBannerType)type 269 | duration:(NSTimeInterval)duration 270 | userDissmissedCallback:(void (^)(MBLMessageBannerView *))userDissmissedCallback 271 | atPosition:(MBLMessageBannerPosition)messagePosition 272 | canBeDismissedByUser:(BOOL)dismissingEnabled { 273 | 274 | [self showMessageBannerInViewController:viewController 275 | title:title 276 | subtitle:subtitle 277 | image:nil 278 | type:type 279 | duration:duration 280 | userDissmissedCallback:userDissmissedCallback 281 | buttonTitle:nil 282 | userPressedButtonCallback:nil 283 | atPosition:messagePosition 284 | canBeDismissedByUser:dismissingEnabled 285 | delegate:nil]; 286 | } 287 | 288 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 289 | title:(NSString *)title 290 | subtitle:(NSString *)subtitle 291 | image:(UIImage *)image 292 | type:(MBLMessageBannerType)type 293 | duration:(NSTimeInterval)duration 294 | userDissmissedCallback:(void (^)(MBLMessageBannerView *))userDissmissedCallback 295 | atPosition:(MBLMessageBannerPosition)messagePosition 296 | canBeDismissedByUser:(BOOL)dismissingEnabled { 297 | [self showMessageBannerInViewController:viewController 298 | title:title 299 | subtitle:subtitle 300 | image:image 301 | type:type 302 | duration:duration 303 | userDissmissedCallback:userDissmissedCallback 304 | buttonTitle:nil 305 | userPressedButtonCallback:nil 306 | atPosition:messagePosition 307 | canBeDismissedByUser:dismissingEnabled 308 | delegate:nil]; 309 | } 310 | 311 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 312 | title:(NSString *)title 313 | subtitle:(NSString *)subtitle 314 | image:(UIImage *)image 315 | type:(MBLMessageBannerType)type 316 | duration:(NSTimeInterval)duration 317 | userDissmissedCallback:(void (^)(MBLMessageBannerView *bannerView))userDissmissedCallback 318 | buttonTitle:(NSString *)buttonTitle 319 | userPressedButtonCallback:(void (^)(MBLMessageBannerView* banner))userPressedButtonCallback 320 | atPosition:(MBLMessageBannerPosition)messagePosition 321 | canBeDismissedByUser:(BOOL)dismissingEnabled 322 | delegate:(id)aDelegate { 323 | 324 | if (!viewController) { 325 | viewController = [MBLMessageBanner defaultViewController]; 326 | } 327 | 328 | MBLMessageBannerView *messageBannerView = [[MBLMessageBannerView alloc] initWithTitle:title subtitle:subtitle image:image type:type duration:duration inViewController:viewController userDissmissedCallback:userDissmissedCallback buttonTitle:buttonTitle userPressedButtonCallback:userPressedButtonCallback atPosition:messagePosition canBeDismissedByUser:dismissingEnabled]; 329 | 330 | if (_delegate == nil) { 331 | [MBLMessageBanner setMessageBannerDelegate:aDelegate]; 332 | } 333 | [self showMessageBanner:messageBannerView]; 334 | } 335 | 336 | #pragma mark - 337 | #pragma mark Fade-in Message Banner methods 338 | 339 | - (UIViewController *)getParentViewController:(MBLMessageBannerView*)message { 340 | UIViewController *parentViewController; 341 | 342 | if ([self isViewControllerOrParentViewControllerNavigationController:message]) { 343 | // Getting the current view Controller 344 | UINavigationController *currentNavigationController; 345 | if ([self isViewControllerNavigationController:message]) { 346 | currentNavigationController = (UINavigationController *)message.viewController; 347 | } else { 348 | currentNavigationController = (UINavigationController *)message.viewController.parentViewController; 349 | } 350 | switch (message.position) { 351 | case MBLMessageBannerPositionTop: 352 | if ([self isNavigationBarVisible:currentNavigationController]) { 353 | parentViewController = currentNavigationController; 354 | } 355 | else { 356 | parentViewController = message.viewController; 357 | } 358 | break; 359 | case MBLMessageBannerPositionCenter: { 360 | parentViewController = message.viewController; 361 | break; 362 | } 363 | case MBLMessageBannerPositionBottom: 364 | if ([self isToolBarHidden:currentNavigationController]) { 365 | parentViewController = currentNavigationController; 366 | } 367 | else { 368 | parentViewController = message.viewController; 369 | } 370 | break; 371 | 372 | default: 373 | break; 374 | } 375 | } 376 | else { 377 | parentViewController = message.viewController; 378 | } 379 | 380 | return parentViewController; 381 | } 382 | 383 | -(void)attachVerticalBannerConstraint:(MBLMessageBannerView*)message onViewController:(UIViewController*)viewController { 384 | 385 | switch (message.position) { 386 | case MBLMessageBannerPositionTop: { 387 | UIViewController* realViewController; 388 | 389 | if ([viewController isKindOfClass:[UINavigationController class]]) { 390 | realViewController = [(UINavigationController*)viewController visibleViewController]; 391 | } else { 392 | realViewController = viewController; 393 | } 394 | 395 | [viewController.view addConstraint:[NSLayoutConstraint constraintWithItem:realViewController.topLayoutGuide 396 | attribute:NSLayoutAttributeBottom 397 | relatedBy:NSLayoutRelationEqual 398 | toItem:message 399 | attribute:NSLayoutAttributeTop 400 | multiplier:1.0f 401 | constant:0.0f]]; 402 | break; 403 | } 404 | case MBLMessageBannerPositionCenter: { 405 | 406 | [viewController.view addConstraint: 407 | [NSLayoutConstraint constraintWithItem:viewController.view 408 | attribute:NSLayoutAttributeCenterY 409 | relatedBy:NSLayoutRelationEqual 410 | toItem:message 411 | attribute:NSLayoutAttributeCenterY 412 | multiplier:1.0f 413 | constant:0.0f]]; 414 | break; 415 | } 416 | case MBLMessageBannerPositionBottom: { 417 | 418 | UIViewController* realViewController; 419 | 420 | if ([viewController isKindOfClass:[UINavigationController class]]) { 421 | realViewController = [(UINavigationController*)viewController visibleViewController]; 422 | } else { 423 | realViewController = viewController; 424 | } 425 | 426 | [viewController.view addConstraint: 427 | [NSLayoutConstraint constraintWithItem:realViewController.bottomLayoutGuide 428 | attribute:NSLayoutAttributeTop 429 | relatedBy:NSLayoutRelationEqual 430 | toItem:message 431 | attribute:NSLayoutAttributeBottom 432 | multiplier:1.0f 433 | constant:0.0f]]; 434 | break; 435 | } 436 | default: 437 | break; 438 | } 439 | } 440 | 441 | -(void)attachBannerConstraints:(MBLMessageBannerView*)message onViewController:(UIViewController*)viewController { 442 | 443 | // Adding horizontal allignment 444 | [viewController.view addConstraint: 445 | [NSLayoutConstraint constraintWithItem:viewController.view 446 | attribute:NSLayoutAttributeWidth 447 | relatedBy:NSLayoutRelationEqual 448 | toItem:message 449 | attribute:NSLayoutAttributeWidth 450 | multiplier:1.0f 451 | constant:0.0f] 452 | ]; 453 | 454 | [viewController.view addConstraints: 455 | [NSLayoutConstraint constraintsWithVisualFormat: @"H:|-0-[message]-0-|" 456 | options: 0 457 | metrics: nil 458 | views: NSDictionaryOfVariableBindings(message)] 459 | ]; 460 | 461 | [self attachVerticalBannerConstraint:message onViewController:viewController]; 462 | 463 | } 464 | 465 | - (void)showMessageBannerOnScreen { 466 | 467 | _messageOnScreen = YES; 468 | 469 | if (![[MBLMessageBanner sharedSingleton].messagesBannersList count]) { 470 | NSLog(@"No Message Banner to show"); 471 | return; 472 | } 473 | 474 | MBLMessageBannerView *currentMessageBanner = [[MBLMessageBanner sharedSingleton].messagesBannersList firstObject]; 475 | 476 | if (_delegate && _delegateRespondTo.messageBannerViewWillAppear == YES) { 477 | [_delegate messageBannerViewWillAppear:currentMessageBanner]; 478 | } 479 | [[NSNotificationCenter defaultCenter] postNotificationName:MESSAGE_BANNER_VIEW_WILL_APPEAR_NOTIFICATION object:currentMessageBanner]; 480 | 481 | [currentMessageBanner setBlur]; 482 | 483 | CGPoint target = [self calculateTargetCenter:currentMessageBanner]; 484 | [self attachBannerConstraints:currentMessageBanner onViewController:[self getParentViewController:currentMessageBanner]]; 485 | 486 | [UIView animateKeyframesWithDuration:ANIMATION_DURATION delay:0.0f options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction animations:^{ 487 | 488 | 489 | currentMessageBanner.center = target; 490 | 491 | } completion:^(BOOL finished) { 492 | 493 | currentMessageBanner.isBannerDisplayed = YES; 494 | if (_delegate && _delegateRespondTo.messageBannerViewDidAppear == YES) { 495 | [_delegate messageBannerViewDidAppear:currentMessageBanner]; 496 | } 497 | [[NSNotificationCenter defaultCenter] postNotificationName:MESSAGE_BANNER_VIEW_DID_APPEAR_NOTIFICATION object:currentMessageBanner]; 498 | }]; 499 | 500 | [self initAutoDismissTimerforBanner:currentMessageBanner]; 501 | } 502 | 503 | #pragma mark - 504 | #pragma mark Hide Message Banner methods 505 | 506 | + (BOOL)hideMessageBanner { 507 | return [self hideMessageBannerWithCompletion:nil]; 508 | } 509 | 510 | + (BOOL) hideMessageBannerWithCompletion:(void (^)())completion { 511 | BOOL success = NO; 512 | 513 | if ([[[MBLMessageBanner sharedSingleton] messagesBannersList] count]) { 514 | success = YES; 515 | dispatch_async(dispatch_get_main_queue(), ^ 516 | { 517 | if ([[[MBLMessageBanner sharedSingleton] messagesBannersList] count]) { 518 | 519 | MBLMessageBannerView *currentView = [[[MBLMessageBanner sharedSingleton] messagesBannersList] objectAtIndex:0]; 520 | if (currentView.isBannerDisplayed) 521 | { 522 | [[MBLMessageBanner sharedSingleton] hideMessageBanner:currentView withGesture:nil andCompletion:completion]; 523 | } 524 | } 525 | }); 526 | 527 | } 528 | return success; 529 | } 530 | 531 | #pragma mark - 532 | #pragma mark Fade-out Message Banner methods 533 | 534 | - (void) hideMessageBanner:(MBLMessageBannerView *)message withGesture:(UIGestureRecognizer *)gesture andCompletion:(void (^)())completion { 535 | 536 | // Removing timer Callback 537 | message.isBannerDisplayed = NO; 538 | 539 | if (message.duration != MBLMessageBannerDurationEndless) { 540 | [message.dismissTimer invalidate]; 541 | } 542 | 543 | if (_delegate && _delegateRespondTo.messageBannerViewWillDisappear == YES) { 544 | [_delegate messageBannerViewWillDisappear:message]; 545 | } 546 | [[NSNotificationCenter defaultCenter] postNotificationName:MESSAGE_BANNER_VIEW_WILL_DISAPPEAR_NOTIFICATION object:message]; 547 | 548 | [message unsetBlur]; 549 | 550 | CGPoint fadeOutCenter = CGPointMake(0, 0); 551 | 552 | switch (message.position) { 553 | case MBLMessageBannerPositionTop: 554 | fadeOutCenter = CGPointMake( message.center.x 555 | , -(message.frame.size.height / 2.0f) ); 556 | break; 557 | case MBLMessageBannerPositionBottom: 558 | fadeOutCenter = CGPointMake( message.center.x 559 | , message.viewController.view.bounds.size.height + (message.frame.size.height / 2.0f) ); 560 | break; 561 | case MBLMessageBannerPositionCenter: 562 | if ([gesture isKindOfClass:[UISwipeGestureRecognizer class]]) { 563 | 564 | UISwipeGestureRecognizer *swipeGesture = (UISwipeGestureRecognizer*)gesture; 565 | switch (swipeGesture.direction) { 566 | 567 | case UISwipeGestureRecognizerDirectionLeft: 568 | fadeOutCenter = CGPointMake( -(message.center.x) 569 | , message.center.y); 570 | break; 571 | case UISwipeGestureRecognizerDirectionRight: 572 | fadeOutCenter = CGPointMake( message.center.x + message.viewController.view.bounds.size.width 573 | , message.center.y); 574 | default: 575 | break; 576 | } 577 | } else { 578 | fadeOutCenter = CGPointMake( -(message.center.x) 579 | , message.center.y); 580 | } 581 | break; 582 | 583 | default: 584 | break; 585 | } 586 | 587 | [UIView animateWithDuration:ANIMATION_DURATION animations:^{ 588 | [message setCenter:fadeOutCenter]; 589 | } completion:^(BOOL finished) { 590 | [message removeFromSuperview]; 591 | [[[MBLMessageBanner sharedSingleton] messagesBannersList] removeObjectAtIndex:0]; 592 | [MBLMessageBanner sharedSingleton].messageOnScreen = NO; 593 | 594 | if (completion) { 595 | completion(); 596 | } 597 | 598 | 599 | if (_delegate && _delegateRespondTo.messageBannerViewDidDisappear == YES) { 600 | [_delegate messageBannerViewDidDisappear:message]; 601 | } 602 | [[NSNotificationCenter defaultCenter] postNotificationName:MESSAGE_BANNER_VIEW_DID_DISAPPEAR_NOTIFICATION object:message]; 603 | 604 | 605 | if ([[[MBLMessageBanner sharedSingleton] messagesBannersList] count]) { 606 | [[MBLMessageBanner sharedSingleton] showMessageBannerOnScreen]; 607 | } 608 | 609 | }]; 610 | } 611 | 612 | #pragma mark - 613 | #pragma mark Message Banner Timer method 614 | 615 | - (void) initAutoDismissTimerforBanner:(MBLMessageBannerView *)message { 616 | CGFloat timerSec = ANIMATION_DURATION; 617 | 618 | if (message.duration != MBLMessageBannerDurationEndless) { 619 | 620 | if (message.duration == MBLMessageBannerDurationDefault) { 621 | timerSec += DISPLAY_DEFAULT_DURATION + (message.frame.size.height * DISPLAY_TIME_PER_PIXEL); 622 | } else { 623 | timerSec += message.duration; 624 | } 625 | 626 | UITapGestureRecognizer *tap = nil; 627 | void (^completion)() = nil; 628 | NSMethodSignature *meth = [[MBLMessageBanner sharedSingleton]methodSignatureForSelector:@selector(hideMessageBanner:withGesture:andCompletion:)]; 629 | NSInvocation *hideMethodInvocation = [NSInvocation invocationWithMethodSignature:meth]; 630 | [hideMethodInvocation setSelector:@selector(hideMessageBanner:withGesture:andCompletion:)]; 631 | [hideMethodInvocation setTarget:[MBLMessageBanner sharedSingleton]]; 632 | [hideMethodInvocation setArgument:&message atIndex:2]; 633 | [hideMethodInvocation setArgument:&tap atIndex:3]; 634 | [hideMethodInvocation setArgument:&completion atIndex:4]; 635 | [hideMethodInvocation retainArguments]; 636 | 637 | dispatch_async(dispatch_get_main_queue(), ^{ 638 | message.dismissTimer = [NSTimer scheduledTimerWithTimeInterval:timerSec invocation:hideMethodInvocation repeats:NO]; 639 | }); 640 | } 641 | } 642 | 643 | #pragma mark - 644 | #pragma mark Calculate new center methods 645 | - (CGFloat) getStatusBarSize { 646 | BOOL isPortrait = UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]); 647 | CGSize statusBarSize = [UIApplication sharedApplication].statusBarFrame.size; 648 | CGFloat offset = isPortrait ? statusBarSize.height : statusBarSize.width; 649 | 650 | return (offset); 651 | } 652 | 653 | -(CGFloat)calculateTopOffsetAndAttachView:(MBLMessageBannerView *)message { 654 | CGFloat topOffset = 0.0f; 655 | 656 | // If has a navigationController 657 | if ([self isViewControllerOrParentViewControllerNavigationController:message]) { 658 | 659 | // Getting the current view Controller 660 | UINavigationController *currentNavigationController; 661 | if ([self isViewControllerNavigationController:message]) { 662 | currentNavigationController = (UINavigationController *)message.viewController; 663 | } else { 664 | currentNavigationController = (UINavigationController *)message.viewController.parentViewController; 665 | } 666 | 667 | // If the navigationBar is visible we add his height as an offset 668 | if ([self isNavigationBarVisible:currentNavigationController]) { 669 | // Adding the view on the navcontroller 670 | [currentNavigationController.view insertSubview:message belowSubview:[currentNavigationController navigationBar]]; 671 | 672 | topOffset += [currentNavigationController navigationBar].bounds.size.height; 673 | } else { 674 | [message.viewController.view addSubview:message]; 675 | } 676 | } else { 677 | [message.viewController.view addSubview:message]; 678 | } 679 | topOffset += [self getStatusBarSize]; 680 | return topOffset; 681 | } 682 | 683 | -(CGFloat)calculateBottomOffsetAndAttachView:(MBLMessageBannerView *)message { 684 | CGFloat bottomOffset = 0.0f; 685 | UINavigationController *currentNavigationController; 686 | 687 | if ([self isViewControllerOrParentViewControllerNavigationController:message]) { 688 | 689 | // Getting the current view Controller 690 | if ([self isViewControllerNavigationController:message]) { 691 | currentNavigationController = (UINavigationController *)message.viewController; 692 | } else { 693 | currentNavigationController = (UINavigationController *)message.viewController.parentViewController; 694 | } 695 | } else { 696 | currentNavigationController = message.viewController.navigationController; 697 | } 698 | 699 | if ([self isToolBarHidden:currentNavigationController]) { 700 | bottomOffset = (currentNavigationController.toolbar.frame.size.height); 701 | [currentNavigationController.view insertSubview:message belowSubview:currentNavigationController.toolbar]; 702 | } else { 703 | [message.viewController.view addSubview:message]; 704 | } 705 | return bottomOffset; 706 | } 707 | 708 | 709 | - (CGPoint)calculateTargetCenter:(MBLMessageBannerView *)message { 710 | CGPoint result; 711 | 712 | switch (message.position) { 713 | case MBLMessageBannerPositionTop: 714 | result = CGPointMake( message.center.x 715 | , (message.frame.size.height / 2.0f) + [self calculateTopOffsetAndAttachView:message]); 716 | break; 717 | case MBLMessageBannerPositionBottom: 718 | result = CGPointMake( message.center.x, message.viewController.view.frame.size.height - ((message.frame.size.height / 2.0f) + [self calculateBottomOffsetAndAttachView:message])); 719 | break; 720 | case MBLMessageBannerPositionCenter: 721 | 722 | // Adding the popup to the view 723 | [message.viewController.view addSubview:message]; 724 | 725 | result = CGPointMake( message.viewController.view.center.x 726 | , message.center.y); 727 | break; 728 | default: 729 | break; 730 | } 731 | return (result); 732 | } 733 | 734 | #pragma mark - 735 | #pragma mark Checks Methods 736 | 737 | - (BOOL)isViewControllerOrParentViewControllerNavigationController:(MBLMessageBannerView *)message { 738 | return ([message.viewController isKindOfClass:[UINavigationController class]] 739 | || [message.viewController.parentViewController isKindOfClass:[UINavigationController class]]); 740 | } 741 | 742 | - (BOOL)isViewControllerNavigationController:(MBLMessageBannerView *)message { 743 | return ([message.viewController isKindOfClass:[UINavigationController class]]); 744 | } 745 | 746 | - (BOOL)isNavigationBarVisible:(UINavigationController *)currentNavigationController { 747 | return (![currentNavigationController isNavigationBarHidden] && 748 | ![[currentNavigationController navigationBar] isHidden]); 749 | } 750 | 751 | - (BOOL)isToolBarHidden:(UINavigationController *)currentNavigationController { 752 | return (currentNavigationController && currentNavigationController.isToolbarHidden == NO); 753 | } 754 | 755 | @end 756 | -------------------------------------------------------------------------------- /MessageBanner/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Thibault Carpentier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /MessageBanner/Ressources/Configuration Files/MessageBannerDesign.json: -------------------------------------------------------------------------------- 1 | { 2 | "Error": { 3 | "defaultImageForType" : "ErrorDefaultLeftImage.pngYOUWISH" 4 | 5 | ,"blurRadius" : 20.0 6 | 7 | ,"backgroundColor" : "#EC736B" 8 | ,"backgroundImageName" : "ErrorBackgroundDefaultImage.pngNO" 9 | ,"backgroundAlpha" : 0.98 10 | 11 | ,"titleTextColor" : "#97000D" 12 | ,"titleTextSize" : 14 13 | ,"titleTextShadowColor" : "#FFFFFF" 14 | ,"titleTextShadowAlpha" : 0.25 15 | ,"titleTextShadowOffsetX" : 0 16 | ,"titleTextShadowOffsetY" : 1 17 | 18 | ,"subtitleTextColor" : "#F0F0F0" 19 | ,"subtitleTextSize" : 12 20 | ,"subtitleTextShadowColor" : "#000000" 21 | ,"subtitleTextShadowAlpha" : 0.25 22 | ,"subtitleTextShadowOffsetX" : 0 23 | ,"subtitleTextShadowOffsetY" : 1 24 | 25 | ,"buttonBackgroundColor" : "#97000D" 26 | ,"buttonBackgroundImage" : "CustomBackgroundImage.pngNOT_ACTIVE" 27 | ,"buttonBackgroundPatternImage" : "CustomBackgroundPattern.pngNOT_ACTIVE" 28 | ,"buttonBackgroundAlpha" : 0.98 29 | ,"buttonCornerRadius" : 5.0 30 | ,"buttonBorderColor" : "#FFFFFF" 31 | ,"buttonBorderAlpha" : 0.75 32 | ,"buttonBorderSize" : 0.0 33 | ,"buttonTextColor" : "#F0F0F0" 34 | ,"buttonTextShadowColor" : "#000000" 35 | ,"buttonTextShadowAlpha" : 0.1 36 | ,"buttonTextShadowOffsetX" : 0 37 | ,"buttonTextShadowOffsetY" : 1 38 | }, 39 | 40 | "Warning": { 41 | "defaultImageForType" : "WarningDefaultLeftImage.png" 42 | 43 | ,"blurRadius" : 0.0 44 | 45 | ,"backgroundColor" : "#F19B2C" 46 | ,"backgroundImageName" : "WarningBackgroundDefaultImage.pngNOT" 47 | ,"backgroundAlpha" : 0.98 48 | 49 | ,"titleTextColor" : "#FDE4C6" 50 | ,"titleTextSize" : 14 51 | ,"titleTextShadowColor" : "#000000" 52 | ,"titleTextShadowAlpha" : 0.25 53 | ,"titleTextShadowOffsetX" : 0 54 | ,"titleTextShadowOffsetY" : 1 55 | 56 | ,"subtitleTextColor" : "#000000" 57 | ,"subtitleTextSize" : 12 58 | ,"subtitleTextShadowColor" : "#FFFFFF" 59 | ,"subtitleTextShadowAlpha" : 0.25 60 | ,"subtitleTextShadowOffsetX" : 0 61 | ,"subtitleTextShadowOffsetY" : 1 62 | 63 | ,"buttonBackgroundColor" : "#FDE4C6" 64 | ,"buttonBackgroundImage" : "CustomBackgroundImage.pngNOT_ACTIVE" 65 | ,"buttonBackgroundPatternImage" : "CustomBackgroundPattern.pngNOT_ACTIVE" 66 | ,"buttonBackgroundAlpha" : 0.98 67 | ,"buttonCornerRadius" : 5.0 68 | ,"buttonBorderColor" : "#FFFFFF" 69 | ,"buttonBorderAlpha" : 0.75 70 | ,"buttonBorderSize" : 0.0 71 | ,"buttonTextColor" : "#000000" 72 | ,"buttonTextShadowColor" : "#FFFFFF" 73 | ,"buttonTextShadowAlpha" : 0.1 74 | ,"buttonTextShadowOffsetX" : 0 75 | ,"buttonTextShadowOffsetY" : 1 76 | }, 77 | 78 | "Message": { 79 | "defaultImageForType" : "MessageDefaultLeftImage.png" 80 | 81 | ,"blurRadius" : 0.0 82 | 83 | ,"backgroundColor" : "#87D3F2" 84 | ,"backgroundImageName" : "MessageBackgroundDefaultImage.pngNOT_ACTIVE" 85 | ,"backgroundAlpha" : 0.98 86 | 87 | ,"titleTextColor" : "#2A7AB7" 88 | ,"titleTextSize" : 14 89 | ,"titleTextShadowColor" : "#FFFFFF" 90 | ,"titleTextShadowAlpha" : 0.25 91 | ,"titleTextShadowOffsetX" : 0 92 | ,"titleTextShadowOffsetY" : 1 93 | 94 | ,"subtitleTextColor" : "#FFFFFF" 95 | ,"subtitleTextSize" : 12 96 | ,"subtitleTextShadowColor" : "#000000" 97 | ,"subtitleTextShadowAlpha" : 0.25 98 | ,"subtitleTextShadowOffsetX" : 0 99 | ,"subtitleTextShadowOffsetY" : 1 100 | 101 | ,"buttonBackgroundColor" : "#2A7AB7" 102 | ,"buttonBackgroundImage" : "CustomBackgroundImage.pngNOT_ACTIVE" 103 | ,"buttonBackgroundPatternImage" : "CustomBackgroundPattern.pngNOT_ACTIVE" 104 | ,"buttonBackgroundAlpha" : 0.98 105 | ,"buttonCornerRadius" : 5.0 106 | ,"buttonBorderColor" : "#FFFFFF" 107 | ,"buttonBorderAlpha" : 0.75 108 | ,"buttonBorderSize" : 0.0 109 | ,"buttonTextColor" : "#FFFFFF" 110 | ,"buttonTextShadowColor" : "#000000" 111 | ,"buttonTextShadowAlpha" : 0.1 112 | ,"buttonTextShadowOffsetX" : 0 113 | ,"buttonTextShadowOffsetY" : 1 114 | }, 115 | 116 | "Success": { 117 | "defaultImageForType" : "SuccessDefaultLeftImage.png" 118 | 119 | ,"blurRadius" : 0.0 120 | 121 | ,"backgroundColor" : "#78EE8A" 122 | ,"backgroundImageName" : "SuccessBackgroundDefaultImage.pngNO" 123 | ,"backgroundAlpha" : 0.98 124 | 125 | ,"titleTextColor" : "#3BAF4A" 126 | ,"titleTextSize" : 14 127 | ,"titleTextShadowColor" : "#FFFFFF" 128 | ,"titleTextShadowAlpha" : 0.25 129 | ,"titleTextShadowOffsetX" : 0 130 | ,"titleTextShadowOffsetY" : 1 131 | 132 | ,"subtitleTextColor" : "#FFFFFF" 133 | ,"subtitleTextSize" : 12 134 | ,"subtitleTextShadowColor" : "#3BAF4A" 135 | ,"subtitleTextShadowAlpha" : 0.25 136 | ,"subtitleTextShadowOffsetX" : 0 137 | ,"subtitleTextShadowOffsetY" : 1 138 | 139 | ,"buttonBackgroundColor" : "#3BAF4A" 140 | ,"buttonBackgroundImage" : "CustomBackgroundImage.pngNOT_ACTIVE" 141 | ,"buttonBackgroundPatternImage" : "CustomBackgroundPattern.pngNOT_ACTIVE" 142 | ,"buttonBackgroundAlpha" : 0.98 143 | ,"buttonCornerRadius" : 5.0 144 | ,"buttonBorderColor" : "#FFFFFF" 145 | ,"buttonBorderAlpha" : 0.75 146 | ,"buttonBorderSize" : 0.0 147 | ,"buttonTextColor" : "#FFFFFF" 148 | ,"buttonTextShadowColor" : "#000000" 149 | ,"buttonTextShadowAlpha" : 0.1 150 | ,"buttonTextShadowOffsetX" : 0 151 | ,"buttonTextShadowOffsetY" : 1 152 | } 153 | } -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/ErrorBackgroundDefaultImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/ErrorBackgroundDefaultImage.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/ErrorBackgroundDefaultImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/ErrorBackgroundDefaultImage@2x.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/ErrorDefaultLeftImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/ErrorDefaultLeftImage.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/ErrorDefaultLeftImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/ErrorDefaultLeftImage@2x.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/MessageBackgroundDefaultImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/MessageBackgroundDefaultImage.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/MessageBackgroundDefaultImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/MessageBackgroundDefaultImage@2x.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/MessageDefaultLeftImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/MessageDefaultLeftImage.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/MessageDefaultLeftImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/MessageDefaultLeftImage@2x.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/SuccessBackgroundDefaultImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/SuccessBackgroundDefaultImage.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/SuccessBackgroundDefaultImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/SuccessBackgroundDefaultImage@2x.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/SuccessDefaultLeftImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/SuccessDefaultLeftImage.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/SuccessDefaultLeftImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/SuccessDefaultLeftImage@2x.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/WarningBackgroundDefaultImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/WarningBackgroundDefaultImage.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/WarningBackgroundDefaultImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/WarningBackgroundDefaultImage@2x.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/WarningDefaultLeftImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/WarningDefaultLeftImage.png -------------------------------------------------------------------------------- /MessageBanner/Ressources/Images/WarningDefaultLeftImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/MessageBanner/Ressources/Images/WarningDefaultLeftImage@2x.png -------------------------------------------------------------------------------- /MessageBanner/Views/MBLMessageBannerView.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MessageBanneviewr.h 3 | * @Author Thibault Carpentier 4 | * @date 2014 5 | * @brief MBLMessageBannerView popup flat styled view. 6 | * 7 | * MBLMessageBannerView a customisable popupview 8 | */ 9 | 10 | #import 11 | #import "MBLMessageBanner.h" 12 | 13 | @interface MBLMessageBannerView : UIView 14 | 15 | /** 16 | The banner title 17 | */ 18 | @property (nonatomic, readonly, copy) NSString* titleBanner; 19 | /** 20 | The banner subtitle 21 | */ 22 | @property (nonatomic, readonly, copy) NSString* subTitle; 23 | /** 24 | The banner left image 25 | */ 26 | @property (nonatomic, readonly, copy) UIImage* image; 27 | /** 28 | The type of the banner 29 | */ 30 | @property (nonatomic, readonly, assign) MBLMessageBannerType bannerType; 31 | /** 32 | The banner setted duration 33 | */ 34 | @property (nonatomic, readonly, assign) CGFloat duration; 35 | /** 36 | The viewController to attach the banner on 37 | */ 38 | @property (nonatomic, readonly) UIViewController* viewController; 39 | /** 40 | The callback called when the user dismiss the popup 41 | */ 42 | @property (nonatomic, readonly, copy) void (^userDissmissedCallback)(MBLMessageBannerView* banner); 43 | /** 44 | The right button title 45 | */ 46 | @property (nonatomic, readonly, copy) NSString* buttonTitle; 47 | /** 48 | The button callback 49 | */ 50 | @property (nonatomic, readonly, copy) void (^userPressedButtonCallback)(MBLMessageBannerView* banner); 51 | /** 52 | The banner position 53 | */ 54 | @property (nonatomic, readonly, assign) MBLMessageBannerPosition position; 55 | /** 56 | Determine if a user can dismiss or no a banner 57 | */ 58 | @property (nonatomic, readonly, assign) BOOL userDismissEnabled; 59 | /** 60 | The timer of the banner 61 | */ 62 | @property (nonatomic, strong) NSTimer* dismissTimer; 63 | /** 64 | Actual display state of the banner 65 | */ 66 | @property (nonatomic, assign) BOOL isBannerDisplayed; 67 | /** 68 | The banner design dictionnary 69 | */ 70 | @property (nonatomic, readonly, copy) NSDictionary *currentDesign; 71 | /** 72 | The message view height used for calculs 73 | */ 74 | @property (nonatomic, readonly, assign) CGFloat messageViewHeight; 75 | 76 | /** 77 | Create a message banner 78 | 79 | @param title The title of the message banner 80 | @param subtitle The subtitle of the message banner 81 | @param image The image to show on the left of the message banner 82 | @param type The type of the message banner @see MBLMessageBannerType values 83 | @param duration The popup duration on screen @see MBLMessageBannerDuration for specials durations 84 | @param viewController The view where the message banner will be added 85 | @param userDissmissedCallback A callback when the user dismiss the popup 86 | @param buttonTitle Enable a button on the right of the view created with this title 87 | @param userPressedButtonCallback A callback when the user press the button 88 | @param messagePosition The position of the message banner @see MBLMessageBannerPosition values 89 | @param dismissingEnabled Enable/Disable user dismiss on the message banner 90 | */ 91 | - (id)initWithTitle:(NSString *)title 92 | subtitle:(NSString *)subtitle 93 | image:(UIImage *)image 94 | type:(MBLMessageBannerType)bannerType 95 | duration:(CGFloat)duration 96 | inViewController:(UIViewController *)viewController 97 | userDissmissedCallback:(void (^)(MBLMessageBannerView* banner))callback 98 | buttonTitle:(NSString *)buttonTitle 99 | userPressedButtonCallback:(void (^)(MBLMessageBannerView *banner))userPressedButtonCallback 100 | atPosition:(MBLMessageBannerPosition)position 101 | canBeDismissedByUser:(BOOL)dismissingEnabled; 102 | 103 | /** 104 | Load a custom design file 105 | @param file the new design file 106 | @returns value YES if the new file is loaded, NO otherwise. 107 | */ 108 | + (BOOL)addMessageBannerDesignFromFileNamed:(NSString *)file; 109 | /** 110 | Return the currently set design file. 111 | @returns the current design file. 112 | */ 113 | + (NSMutableDictionary *)messageBannerDesign; 114 | 115 | /** 116 | Set the default design file. 117 | @returns void 118 | */ 119 | + (void)setDefaultDesignFile:(NSString *)fileName; 120 | 121 | @end -------------------------------------------------------------------------------- /MessageBanner/Views/MBLMessageBannerView.m: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MessageBanneviewr.m 3 | * @Author Thibault Carpentier 4 | * @date 2014 5 | * @brief MBLMessageBannerView popup flat styled view. 6 | * 7 | * MBLMessageBannerView a customisable popupview 8 | */ 9 | 10 | #import "MBLMessageBannerView.h" 11 | #import "MBLMessageBanner.h" 12 | #import "HexColors.h" 13 | #import "FXBlurView.h" 14 | 15 | /** 16 | The default design file 17 | */ 18 | static NSString *defaultDesignFile = @"MessageBannerDesign.json"; 19 | 20 | /** 21 | The label of the error type message banner configuration 22 | */ 23 | #define ERROR_JSON_LABEL @"Error" 24 | /** 25 | The label of the warning type message banner configuration 26 | */ 27 | #define WARNING_JSON_LABEL @"Warning" 28 | /** 29 | The label of the message type message banner configuration 30 | */ 31 | #define MESSAGE_JSON_LABEL @"Message" 32 | /** 33 | The label of the success type message banner configuration 34 | */ 35 | #define SUCCESS_JSON_LABEL @"Success" 36 | 37 | /** 38 | The blur radius key in the design configuration file 39 | */ 40 | #define BLUR_RADIUS_KEY @"blurRadius" 41 | 42 | /** 43 | The background color key in the design configuration file 44 | */ 45 | #define BACKGROUND_COLOR_KEY @"backgroundColor" 46 | /** 47 | The backgorund alpha key in the design configuration file 48 | */ 49 | #define BACKGROUND_ALPHA_KEY @"backgroundAlpha" 50 | /** 51 | The background image key in the design configuration file 52 | */ 53 | #define BACKGROUND_IMAGE_KEY @"backgroundImageName" 54 | 55 | /** 56 | The default left image for the type in the design configuration file 57 | */ 58 | #define DEFAULT_TYPE_IMAGE_KEY @"defaultImageForType" 59 | 60 | /** 61 | The title text size key in the design configuration file 62 | */ 63 | #define TITLE_TEXT_SIZE_KEY @"titleTextSize" 64 | /** 65 | The title text color key in the design configuration file 66 | */ 67 | #define TITLE_TEXT_COLOR_KEY @"titleTextColor" 68 | /** 69 | The title text shadow color key in the design configuration file 70 | */ 71 | #define TITLE_TEXT_SHADOW_COLOR_KEY @"titleTextShadowColor" 72 | /** 73 | The title text shadow X offset key in the design configuration file 74 | */ 75 | #define TITLE_TEXT_SHADOW_OFFSET_X_KEY @"titleTextShadowOffsetX" 76 | /** 77 | The title text shadow Y offset key in the design configuration file 78 | */ 79 | #define TITLE_TEXT_SHADOW_OFFSET_Y_KEY @"titleTextShadowOffsetY" 80 | /** 81 | The the title text shadow alpha key in the design configuration file 82 | */ 83 | #define TITLE_TEXT_SHADOW_ALPHA_KEY @"titleTextShadowAlpha" 84 | 85 | /** 86 | The subtitle text size key in the design configuration file 87 | */ 88 | #define SUBTITLE_TEXT_SIZE_KEY @"subtitleTextSize" 89 | /** 90 | The subtitle text color key in the design configuration file 91 | */ 92 | #define SUBTITLE_TEXT_COLOR_KEY @"subtitleTextColor" 93 | /** 94 | The subtitle text shadow color key in the design configuration file 95 | */ 96 | #define SUBTITLE_TEXT_SHADOW_COLOR_KEY @"subtitleTextShadowColor" 97 | /** 98 | The subtitle text shadow X offset key in the design configuration file 99 | */ 100 | #define SUBTITLE_TEXT_SHADOW_OFFSET_X_KEY @"subtitleTextShadowOffsetX" 101 | /** 102 | The subtitle text shadow Y offset key in the design configuration file 103 | */ 104 | #define SUBTITLE_TEXT_SHADOW_OFFSET_Y_KEY @"subtitleTextShadowOffsetY" 105 | /** 106 | The subtitle text shadow alpha key in the design configuration file 107 | */ 108 | #define SUBTITLE_TEXT_SHADOW_ALPHA_KEY @"subtitleTextShadowAlpha" 109 | 110 | /** 111 | The button background color key in the design configuration file 112 | */ 113 | #define BUTTON_BACKGROUND_COLOR_KEY @"buttonBackgroundColor" 114 | /** 115 | The button background image key in the design configuration file 116 | */ 117 | #define BUTTON_BACKGROUND_IMAGE_KEY @"buttonBackgroundImage" 118 | /** 119 | The button image pattern background key in the design configuration file 120 | */ 121 | #define BUTTON_BACKGROUND_PATTERN_IMAGE_KEY @"buttonBackgroundPatternImage" 122 | /** 123 | The button background alpha key in the design configuration file 124 | */ 125 | #define BUTTON_BACKGROUND_ALPHA_KEY @"buttonBackgroundAlpha" 126 | 127 | /** 128 | The button corener radius key in the design configuration file 129 | */ 130 | #define BUTTON_CORNER_RADIUS_KEY @"buttonCornerRadius" 131 | /** 132 | The button border color key in the design configuration file 133 | */ 134 | #define BUTTON_BORDER_COLOR_KEY @"buttonBorderColor" 135 | /** 136 | The button border alpha key in the design configuration file 137 | */ 138 | #define BUTTON_BORDER_ALPHA_KEY @"buttonBorderAlpha" 139 | /** 140 | The button border size key in the design configuration file 141 | */ 142 | #define BUTTON_BORDER_SIZE_KEY @"buttonBorderSize" 143 | 144 | /** 145 | The button text color key in the design configuration file 146 | */ 147 | #define BUTTON_TEXT_COLOR_KEY @"buttonTextColor" 148 | /** 149 | The button text shadow color key in the design configuration file 150 | */ 151 | #define BUTTON_TEXT_SHADOW_COLOR_KEY @"buttonTextShadowColor" 152 | /** 153 | The button text shadow X offset key in the design configuration file 154 | */ 155 | #define BUTTON_TEXT_SHADOW_OFFSET_X_KEY @"buttonTextShadowOffsetX" 156 | /** 157 | The button text shadow Y offset key in the design configuration file 158 | */ 159 | #define BUTTON_TEXT_SHADOW_OFFSET_Y_KEY @"buttonTextShadowOffsetY" 160 | /** 161 | The button text shadow alpha key in the design configuration file 162 | */ 163 | #define BUTTON_TEXT_SHADOW_ALPHA_KEY @"buttonTextShadowAlpha" 164 | 165 | /** 166 | The default element padding used for positionning 167 | */ 168 | #define ELEMENTS_PADDING 16.0f 169 | 170 | /** 171 | The animation duration used for setting the blur 172 | */ 173 | #define ANIMATION_DURATION 0.5 174 | 175 | /** 176 | Undocumented private methods calls for internal use 177 | */ 178 | @interface MBLMessageBanner (MBLMessageBannerView) 179 | - (void) hideMessageBanner:(MBLMessageBannerView *)messageBanner 180 | withGesture:(UIGestureRecognizer *)gesture 181 | andCompletion:(void (^)())completion; 182 | 183 | - (BOOL)isViewControllerOrParentViewControllerNavigationController:(MBLMessageBannerView *)message; 184 | 185 | - (BOOL)isViewControllerNavigationController:(MBLMessageBannerView *)message; 186 | 187 | - (BOOL)isNavigationBarVisible:(UINavigationController *)currentNavigationController; 188 | 189 | - (BOOL)isToolBarHidden:(UINavigationController *)currentNavigationController; 190 | 191 | @end 192 | 193 | /** 194 | General banner design 195 | */ 196 | static NSMutableDictionary* _messageBannerDesign; 197 | 198 | @interface MBLMessageBannerView () 199 | 200 | /** 201 | The title label view 202 | */ 203 | @property (nonatomic, strong) UILabel* titleLabel; 204 | /** 205 | The subtitle label view 206 | */ 207 | @property (nonatomic, strong) UILabel* subtitleLabel; 208 | /** 209 | The image view 210 | */ 211 | @property (nonatomic, strong) UIImageView* imageView; 212 | /** 213 | The button view 214 | */ 215 | @property (nonatomic, strong) UIButton* button; 216 | /** 217 | The blurr view attached to the viewcontroller if activated 218 | */ 219 | @property (nonatomic, strong) FXBlurView* blurView; 220 | /** 221 | The message view height used for calculs 222 | */ 223 | @property (nonatomic, readwrite, assign) CGFloat messageViewHeight; 224 | 225 | @end 226 | 227 | @implementation MBLMessageBannerView 228 | 229 | 230 | #pragma mark - 231 | #pragma mark Message Banner Design File Methods 232 | 233 | + (BOOL)addMessageBannerDesignFromFileNamed:(NSString *)file { 234 | BOOL success = YES; 235 | NSError* error; 236 | 237 | NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:file]; 238 | NSDictionary* newDesign = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filePath] 239 | options:kNilOptions 240 | error:&error]; 241 | if (error) { 242 | success = NO; 243 | @throw ([NSException exceptionWithName:@"Error loading design" 244 | reason: 245 | [NSString stringWithFormat:@"Can not load %@.\nError:%@", file, error] userInfo:nil]); 246 | } else { 247 | [[MBLMessageBannerView messageBannerDesign] addEntriesFromDictionary:newDesign]; 248 | } 249 | return success; 250 | } 251 | 252 | + (void)setDefaultDesignFile:(NSString *)fileName 253 | { 254 | defaultDesignFile = fileName; 255 | } 256 | 257 | + (NSMutableDictionary *)messageBannerDesign { 258 | if (!_messageBannerDesign) { 259 | NSError* error; 260 | NSString *filePath = [[[NSBundle mainBundle] resourcePath] 261 | stringByAppendingPathComponent:defaultDesignFile]; 262 | _messageBannerDesign = [[NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filePath] 263 | options:kNilOptions 264 | error:&error] mutableCopy]; 265 | 266 | if (error) { 267 | @throw ([NSException exceptionWithName:@"Error loading default design" 268 | reason: 269 | [NSString stringWithFormat:@"Can not load %@.\nError:%@", defaultDesignFile, error] 270 | userInfo:nil]); 271 | } 272 | } 273 | return _messageBannerDesign; 274 | } 275 | 276 | #pragma mark - 277 | #pragma mark Init and dismiss methods 278 | 279 | - (id)initWithTitle:(NSString *)title 280 | subtitle:(NSString *)subtitle 281 | image:(UIImage *)image 282 | type:(MBLMessageBannerType)bannerType 283 | duration:(CGFloat)duration 284 | inViewController:(UIViewController *)viewController 285 | userDissmissedCallback:(void (^)(MBLMessageBannerView* banner))userDissmissedCallback 286 | buttonTitle:(NSString *)buttonTitle 287 | userPressedButtonCallback:(void (^)(MBLMessageBannerView* banner))userPressedButtonCallback 288 | atPosition:(MBLMessageBannerPosition)position 289 | canBeDismissedByUser:(BOOL)dismissingEnabled { 290 | 291 | if ((self = [self init])) { 292 | 293 | _titleBanner = title; 294 | _subTitle = subtitle; 295 | _image = image; 296 | _bannerType = bannerType; 297 | _duration = duration; 298 | _viewController = viewController; 299 | _userDissmissedCallback = userDissmissedCallback; 300 | _buttonTitle = buttonTitle; 301 | _userPressedButtonCallback = userPressedButtonCallback; 302 | 303 | _position = position; 304 | _userDismissEnabled = dismissingEnabled; 305 | 306 | self.messageViewHeight = 0.0f; 307 | _isBannerDisplayed = NO; 308 | 309 | _currentDesign = [[MBLMessageBannerView messageBannerDesign] 310 | objectForKey:[self getStyleTypeLabel:self.bannerType]]; 311 | // Adding Default Image from config 312 | if (_image == nil) { 313 | _image = [UIImage imageNamed:[_currentDesign objectForKey:DEFAULT_TYPE_IMAGE_KEY]]; 314 | } 315 | 316 | // To be declined according to position; 317 | 318 | [self addButtonOnBannerAndSetupFrame:buttonTitle]; 319 | // Setting up title 320 | self.titleLabel = [self createMessageTitle]; 321 | [self addSubview:self.titleLabel]; 322 | 323 | // Setting up subtitle 324 | if (self.subTitle) { 325 | self.subtitleLabel = [self createSubtitleLabel]; 326 | [self addSubview:self.subtitleLabel]; 327 | } 328 | 329 | // Setting up style 330 | [self setupStyleWithType:self.bannerType]; 331 | 332 | // Setting up frames 333 | [self setTitleFrame:self.titleLabel]; 334 | if (self.subTitle) { 335 | [self setSubtitleFrame:self.subtitleLabel]; 336 | } 337 | [self addImageOnBannerAndSetupFrame:self.image]; 338 | [self centerButton]; 339 | // [self setImageFrame:image] 340 | 341 | // Setting message frame : 342 | [self setFrame:[self createViewFrame]]; 343 | 344 | 345 | 346 | // Adding dismiss gesture 347 | if (self.userDismissEnabled) { 348 | [self addDismissMethod]; 349 | } 350 | 351 | } 352 | 353 | [self setupViewsAutoLayout]; 354 | 355 | return self; 356 | } 357 | 358 | #pragma mark - 359 | #pragma mark Autolayout methods 360 | 361 | -(void)layoutSubviews { 362 | [super layoutSubviews]; 363 | } 364 | 365 | - (void)setupViewsAutoLayout { 366 | [self setTranslatesAutoresizingMaskIntoConstraints:NO]; 367 | [self.titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; 368 | [self.subtitleLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; 369 | [self.imageView setTranslatesAutoresizingMaskIntoConstraints:NO]; 370 | [self.button setTranslatesAutoresizingMaskIntoConstraints:NO]; 371 | 372 | [self setupTitleAutoLayout]; 373 | 374 | if (self.subTitle) { 375 | [self setupSubtitleAutoLayout]; 376 | } 377 | 378 | if (self.image) { 379 | [self setupImageAutoLayout]; 380 | } 381 | 382 | if (self.buttonTitle && [self.buttonTitle length]) { 383 | [self setupButtonAutoLayout]; 384 | } 385 | 386 | NSString* widthConstraintVisualFormat = [NSString stringWithFormat:@"V:[self(<=%f)]", 387 | self.messageViewHeight]; 388 | 389 | [self addConstraints: 390 | [NSLayoutConstraint constraintsWithVisualFormat:widthConstraintVisualFormat 391 | options:0 392 | metrics:nil 393 | views:NSDictionaryOfVariableBindings(self)]]; 394 | 395 | } 396 | 397 | #pragma mark - 398 | #pragma mark Dismiss methods 399 | 400 | - (void)addDismissMethod { 401 | // Adding swipe to dismiss if setted 402 | UISwipeGestureRecognizer *dismissGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self 403 | action:@selector(dismissViewWithGesture:)]; 404 | 405 | switch (self.position) { 406 | case MBLMessageBannerPositionTop: 407 | [dismissGesture setDirection:UISwipeGestureRecognizerDirectionUp];; 408 | break; 409 | case MBLMessageBannerPositionBottom: 410 | [dismissGesture setDirection:UISwipeGestureRecognizerDirectionDown]; 411 | break; 412 | case MBLMessageBannerPositionCenter: { 413 | [dismissGesture setDirection:UISwipeGestureRecognizerDirectionLeft]; 414 | UISwipeGestureRecognizer *dismissGesture2 = [[UISwipeGestureRecognizer alloc] initWithTarget:self 415 | action:@selector(dismissViewWithGesture:)]; 416 | [dismissGesture2 setDirection:UISwipeGestureRecognizerDirectionRight]; 417 | [self addGestureRecognizer:dismissGesture2]; 418 | break; 419 | } 420 | default: 421 | 422 | break; 423 | } 424 | [self addGestureRecognizer:dismissGesture]; 425 | 426 | UITapGestureRecognizer *dismissGesture3 = [[UITapGestureRecognizer alloc] initWithTarget:self 427 | action:@selector(dismissViewWithGesture:)]; 428 | [dismissGesture3 setNumberOfTapsRequired:1]; 429 | [self addGestureRecognizer:dismissGesture3]; 430 | } 431 | 432 | #pragma mark - 433 | #pragma mark View Management 434 | 435 | - (void)setBlur { 436 | CGFloat blurRadius = [[_currentDesign objectForKey:BLUR_RADIUS_KEY] floatValue]; 437 | 438 | if (blurRadius != 0.0) { 439 | self.blurView = [[FXBlurView alloc] initWithFrame:self.viewController.view.bounds]; 440 | self.blurView.underlyingView = self.viewController.view; 441 | self.blurView.tintColor = [UIColor clearColor]; 442 | self.blurView.blurRadius = blurRadius; 443 | self.blurView.alpha = 0.f; 444 | 445 | if ([[MBLMessageBanner sharedSingleton] isViewControllerOrParentViewControllerNavigationController:self]) { 446 | if ([[MBLMessageBanner sharedSingleton] isViewControllerNavigationController:self]) { 447 | UIView *correctView = [((UINavigationController *)self.viewController) navigationBar]; 448 | 449 | if (self.position == MBLMessageBannerPositionBottom) { 450 | correctView = [((UINavigationController *)self.viewController) toolbar]; 451 | } 452 | 453 | [((UINavigationController *)self.viewController).view insertSubview:self.blurView 454 | belowSubview:correctView 455 | ]; 456 | 457 | } else { 458 | [((UINavigationController *)self.viewController.parentViewController).visibleViewController.view addSubview:self.blurView]; 459 | } 460 | } 461 | else { 462 | [self.viewController.view addSubview:self.blurView]; 463 | } 464 | 465 | [UIView animateWithDuration:ANIMATION_DURATION animations:^{ 466 | self.blurView.alpha = 1.f; 467 | } completion:nil]; 468 | } 469 | } 470 | 471 | - (void)unsetBlur { 472 | CGFloat blurRadius = [[_currentDesign objectForKey:BLUR_RADIUS_KEY] floatValue]; 473 | 474 | if (blurRadius != 0.0) { 475 | [UIView animateWithDuration:ANIMATION_DURATION animations:^{ 476 | self.blurView.alpha = 0.f; 477 | } completion:^(BOOL finished) { 478 | [self.blurView removeFromSuperview]; 479 | }]; 480 | } 481 | } 482 | 483 | #pragma mark - 484 | #pragma mark View frame methods 485 | - (CGRect) createViewFrame { 486 | CGRect viewFrame; 487 | 488 | // Adding Bottom padding 489 | self.messageViewHeight += ELEMENTS_PADDING; 490 | 491 | switch (self.position) { 492 | case MBLMessageBannerPositionTop: { 493 | 494 | 495 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; 496 | viewFrame = CGRectMake( 0 497 | , 0 - self.messageViewHeight 498 | , self.viewController.view.bounds.size.width 499 | , self.messageViewHeight); 500 | break; 501 | } 502 | case MBLMessageBannerPositionBottom: 503 | 504 | self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); 505 | viewFrame = CGRectMake( 0 506 | , self.viewController.view.bounds.size.height + self.messageViewHeight 507 | , self.viewController.view.bounds.size.width 508 | , self.messageViewHeight); 509 | break; 510 | 511 | case MBLMessageBannerPositionCenter: 512 | 513 | self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); 514 | viewFrame = CGRectMake( -(self.viewController.view.bounds.size.width) 515 | , ((self.viewController.view.bounds.size.height / 2.0f) - (self.messageViewHeight / 2.0f)) 516 | , self.viewController.view.bounds.size.width 517 | , self.messageViewHeight); 518 | break; 519 | 520 | default: 521 | break; 522 | } 523 | 524 | // Used to add constraints when the view will pop 525 | return viewFrame; 526 | } 527 | 528 | #pragma mark - 529 | #pragma mark Title Label methods 530 | 531 | - (UILabel *)createMessageTitle { 532 | UILabel *titleLabel = [[UILabel alloc] init]; 533 | 534 | // Adding title 535 | [titleLabel setText:self.titleBanner]; 536 | 537 | // Changing text appearance 538 | [titleLabel setBackgroundColor:[UIColor clearColor]]; 539 | 540 | // title formating 541 | [titleLabel setNumberOfLines:0]; 542 | [titleLabel setLineBreakMode:NSLineBreakByWordWrapping]; 543 | 544 | return (titleLabel); 545 | } 546 | 547 | - (void)setTitleFrame:(UILabel *)titleView { 548 | CGFloat leftOffset = ELEMENTS_PADDING; 549 | CGFloat rightOffset = ELEMENTS_PADDING; 550 | 551 | // If image then offset the text more 552 | if (self.image != nil) { 553 | leftOffset += (self.image.size.width + (ELEMENTS_PADDING)); 554 | } 555 | 556 | if (self.buttonTitle && [self.buttonTitle length]) { 557 | rightOffset += self.button.frame.size.width + ELEMENTS_PADDING; 558 | } 559 | 560 | 561 | [titleView setFrame:CGRectMake( leftOffset 562 | , ELEMENTS_PADDING 563 | , self.viewController.view.bounds.size.width - leftOffset - rightOffset 564 | , 0.0f 565 | )]; 566 | 567 | // updating height 568 | [titleView sizeToFit]; 569 | 570 | // updating viewHeight 571 | self.messageViewHeight += (titleView.frame.origin.y + titleView.frame.size.height); 572 | } 573 | 574 | -(void)setupTitleAutoLayout { 575 | NSDictionary *titleAndViewDictionary = [[NSMutableDictionary alloc] 576 | initWithDictionary:NSDictionaryOfVariableBindings (_titleLabel, self)]; 577 | 578 | NSMutableDictionary *titleAndImageDictionary = (self.image ? [[NSMutableDictionary alloc] 579 | initWithDictionary:NSDictionaryOfVariableBindings (_titleLabel, _imageView)] : nil); 580 | NSMutableDictionary *titleAndButtonDictionary = (self.button ? [[NSMutableDictionary alloc] initWithDictionary: NSDictionaryOfVariableBindings (_titleLabel, _button)] : nil); 581 | NSMutableDictionary *titleAndSubtitleDictionary = (self.subtitleLabel ? [[NSMutableDictionary alloc] initWithDictionary:NSDictionaryOfVariableBindings (_titleLabel, _subtitleLabel)] : nil); 582 | 583 | 584 | // Top attach layout and bottom : 585 | NSString *topBotConstraintVisualFormat; 586 | NSMutableDictionary *topBotCorrectDictionnary; 587 | 588 | if (!titleAndSubtitleDictionary) { 589 | topBotConstraintVisualFormat = [NSString stringWithFormat:@"V:|-==%f-[_titleLabel]-==%f-|", ELEMENTS_PADDING, ELEMENTS_PADDING]; 590 | topBotCorrectDictionnary = [[NSMutableDictionary alloc] initWithDictionary:titleAndViewDictionary]; 591 | } else { 592 | topBotConstraintVisualFormat = [NSString stringWithFormat:@"V:|-==%f-[_titleLabel]-==%f-[_subtitleLabel]", ELEMENTS_PADDING, ELEMENTS_PADDING]; 593 | topBotCorrectDictionnary = titleAndSubtitleDictionary; 594 | } 595 | [self addConstraints: 596 | [NSLayoutConstraint constraintsWithVisualFormat:topBotConstraintVisualFormat 597 | options:0 598 | metrics:nil 599 | views:topBotCorrectDictionnary]]; 600 | 601 | // Left and right layouuts 602 | NSString *leftRightConstraintVisualFormat; 603 | NSMutableDictionary *leftRightCorrectDictionnary; 604 | 605 | // left positionning 606 | if (titleAndImageDictionary) { 607 | leftRightConstraintVisualFormat = [NSString stringWithFormat:@"H:[_imageView]-==%f-[_titleLabel]", ELEMENTS_PADDING]; 608 | leftRightCorrectDictionnary = titleAndImageDictionary; 609 | } else { 610 | leftRightConstraintVisualFormat = [NSString stringWithFormat:@"H:|-==%f-[_titleLabel]", ELEMENTS_PADDING]; 611 | leftRightCorrectDictionnary = [[NSMutableDictionary alloc] initWithDictionary:titleAndViewDictionary]; 612 | } 613 | 614 | // right positionning 615 | if (titleAndButtonDictionary) { 616 | leftRightConstraintVisualFormat = [NSString stringWithFormat:@"%@-==%f-[_button]" 617 | , leftRightConstraintVisualFormat 618 | , ELEMENTS_PADDING]; 619 | [leftRightCorrectDictionnary addEntriesFromDictionary:titleAndButtonDictionary]; 620 | } else { 621 | leftRightConstraintVisualFormat = [NSString stringWithFormat:@"%@-==%f-|" 622 | , leftRightConstraintVisualFormat 623 | , ELEMENTS_PADDING]; 624 | } 625 | [self addConstraints: 626 | [NSLayoutConstraint constraintsWithVisualFormat:leftRightConstraintVisualFormat 627 | options:0 628 | metrics:nil 629 | views:leftRightCorrectDictionnary]]; 630 | } 631 | 632 | #pragma mark - 633 | #pragma mark Subtitle Label methods 634 | 635 | - (UILabel *)createSubtitleLabel { 636 | UILabel *subtitleLabel = [[UILabel alloc] init]; 637 | 638 | // Adding subtitle 639 | [subtitleLabel setText:self.subTitle]; 640 | 641 | // Changing text appearance 642 | [subtitleLabel setBackgroundColor:[UIColor clearColor]]; 643 | 644 | // subtitle formating 645 | [subtitleLabel setNumberOfLines:0]; 646 | [subtitleLabel setLineBreakMode:NSLineBreakByWordWrapping]; 647 | return (subtitleLabel); 648 | } 649 | 650 | - (void)setSubtitleFrame:(UILabel *)subtitleView { 651 | CGFloat leftOffset = ELEMENTS_PADDING; 652 | CGFloat rightOffset = ELEMENTS_PADDING; 653 | 654 | // If image then offset the text more 655 | if (self.image != nil) { 656 | leftOffset += (self.image.size.width + (ELEMENTS_PADDING)); 657 | } 658 | 659 | if (self.buttonTitle && [self.buttonTitle length]) { 660 | rightOffset += self.button.frame.size.width + ELEMENTS_PADDING; 661 | } 662 | 663 | [subtitleView setFrame:CGRectMake( leftOffset 664 | , (ELEMENTS_PADDING + self.titleLabel.frame.origin.y + self.titleLabel.frame.size.height) 665 | , self.viewController.view.bounds.size.width - leftOffset - rightOffset 666 | , 0.0f 667 | )]; 668 | // updating height 669 | [subtitleView sizeToFit]; 670 | 671 | // updating viewHeight 672 | self.messageViewHeight += (subtitleView.frame.origin.y - self.messageViewHeight) + subtitleView.frame.size.height; 673 | } 674 | 675 | -(void)setupSubtitleAutoLayout { 676 | NSDictionary *subtitleAndViewDictionary = [[NSMutableDictionary alloc] 677 | initWithDictionary:NSDictionaryOfVariableBindings (_subtitleLabel, self)]; 678 | 679 | 680 | 681 | NSMutableDictionary *subtitleAndImageDictionary = (self.image ? [[NSMutableDictionary alloc] 682 | initWithDictionary:NSDictionaryOfVariableBindings (_subtitleLabel, _imageView)] : nil); 683 | NSMutableDictionary *subtitleAndButtonDictionary = (self.button ? [[NSMutableDictionary alloc] initWithDictionary: NSDictionaryOfVariableBindings (_subtitleLabel, _button)] : nil); 684 | NSMutableDictionary *subtitleAndTitleDictionary = (self.subtitleLabel ? [[NSMutableDictionary alloc] initWithDictionary:NSDictionaryOfVariableBindings (_subtitleLabel, _titleLabel)] : nil); 685 | 686 | 687 | // Top attach layout and bottom : 688 | NSString *topBotConstraintVisualFormat; 689 | NSMutableDictionary *topBotCorrectDictionnary; 690 | 691 | topBotConstraintVisualFormat = [NSString stringWithFormat:@"V:[_titleLabel]-==%f-[_subtitleLabel]-==%f-|", ELEMENTS_PADDING, ELEMENTS_PADDING]; 692 | topBotCorrectDictionnary = subtitleAndTitleDictionary; 693 | [self addConstraints: 694 | [NSLayoutConstraint constraintsWithVisualFormat:topBotConstraintVisualFormat 695 | options:0 696 | metrics:nil 697 | views:topBotCorrectDictionnary]]; 698 | 699 | // Left and right layouuts 700 | NSString *leftRightConstraintVisualFormat; 701 | NSMutableDictionary *leftRightCorrectDictionnary; 702 | 703 | // left positionning 704 | if (subtitleAndImageDictionary) { 705 | leftRightConstraintVisualFormat = [NSString stringWithFormat:@"H:[_imageView]-==%f-[_subtitleLabel]", ELEMENTS_PADDING]; 706 | leftRightCorrectDictionnary = subtitleAndImageDictionary; 707 | } else { 708 | leftRightConstraintVisualFormat = [NSString stringWithFormat:@"H:|-==%f-[_subtitleLabel]", ELEMENTS_PADDING]; 709 | leftRightCorrectDictionnary = [[NSMutableDictionary alloc] initWithDictionary:subtitleAndViewDictionary]; 710 | } 711 | 712 | // right positionning 713 | if (subtitleAndButtonDictionary) { 714 | leftRightConstraintVisualFormat = [NSString stringWithFormat:@"%@-==%f-[_button]" 715 | , leftRightConstraintVisualFormat 716 | , ELEMENTS_PADDING]; 717 | [leftRightCorrectDictionnary addEntriesFromDictionary:subtitleAndButtonDictionary]; 718 | } else { 719 | leftRightConstraintVisualFormat = [NSString stringWithFormat:@"%@-==%f-|" 720 | , leftRightConstraintVisualFormat 721 | , ELEMENTS_PADDING]; 722 | } 723 | [self addConstraints: 724 | [NSLayoutConstraint constraintsWithVisualFormat:leftRightConstraintVisualFormat 725 | options:0 726 | metrics:nil 727 | views:leftRightCorrectDictionnary]]; 728 | } 729 | 730 | 731 | #pragma mark - 732 | #pragma mark Image View methods 733 | 734 | - (void)addImageOnBannerAndSetupFrame:(UIImage *)image { 735 | 736 | self.imageView = [[UIImageView alloc] initWithImage:image]; 737 | self.imageView.frame = CGRectMake(ELEMENTS_PADDING, 738 | ((ELEMENTS_PADDING + self.messageViewHeight - image.size.height) /2), 739 | image.size.width, 740 | image.size.height); 741 | 742 | [self addSubview:self.imageView]; 743 | } 744 | 745 | -(void)setupImageAutoLayout { 746 | NSMutableDictionary *imageAndsubTitleDictionary = (self.subTitle ? [[NSMutableDictionary alloc] 747 | initWithDictionary:NSDictionaryOfVariableBindings (_subtitleLabel, _imageView)] : nil); 748 | NSMutableDictionary *imageAndTitleDictionary = (self.titleBanner ? [[NSMutableDictionary alloc] initWithDictionary:NSDictionaryOfVariableBindings (_imageView, _titleLabel)] : nil); 749 | 750 | [self addConstraint: 751 | [NSLayoutConstraint constraintWithItem:self 752 | attribute:NSLayoutAttributeCenterY 753 | relatedBy:NSLayoutRelationEqual 754 | toItem:_imageView 755 | attribute:NSLayoutAttributeCenterY 756 | multiplier:1.0f 757 | constant:0.0f]]; 758 | 759 | 760 | NSString* leftRightConstraintsVisualFormat = [NSString stringWithFormat:@"H:|-==%f-[_imageView]-==%f-[_titleLabel]" 761 | , ELEMENTS_PADDING 762 | , ELEMENTS_PADDING]; 763 | [self addConstraints: 764 | [NSLayoutConstraint constraintsWithVisualFormat:leftRightConstraintsVisualFormat 765 | options:0 766 | metrics:nil 767 | views:imageAndTitleDictionary]]; 768 | if (imageAndsubTitleDictionary) { 769 | [self addConstraints: 770 | [NSLayoutConstraint constraintsWithVisualFormat: 771 | [NSString stringWithFormat:@"H:|-==%f-[_imageView]-==%f-[_subtitleLabel]" 772 | , ELEMENTS_PADDING 773 | , ELEMENTS_PADDING] 774 | options:0 775 | metrics:nil 776 | views:imageAndsubTitleDictionary]]; 777 | } 778 | 779 | 780 | NSString *widthImageFormat = [NSString stringWithFormat:@"[_imageView(==%f)]", 781 | _imageView.frame.size.width]; 782 | [self addConstraints: 783 | [NSLayoutConstraint constraintsWithVisualFormat:widthImageFormat 784 | options:0 785 | metrics:nil 786 | views:NSDictionaryOfVariableBindings(_imageView)]]; 787 | 788 | NSString *heightImageFormat = [NSString stringWithFormat:@"V:[_imageView(==%f)]", 789 | _imageView.frame.size.height]; 790 | [self addConstraints: 791 | [NSLayoutConstraint constraintsWithVisualFormat:heightImageFormat 792 | options:0 793 | metrics:nil 794 | views:NSDictionaryOfVariableBindings(_imageView)]]; 795 | 796 | } 797 | 798 | #pragma mark - 799 | #pragma mark Button methods Button View methods 800 | 801 | - (void)addButtonOnBannerAndSetupFrame:(NSString *)buttonTitle { 802 | 803 | if (buttonTitle && [buttonTitle length]) { 804 | self.button = [UIButton buttonWithType:UIButtonTypeCustom]; 805 | [self.button setTitle:buttonTitle forState:UIControlStateNormal]; 806 | [self.button.titleLabel setFont:[UIFont systemFontOfSize:14.0f]]; 807 | self.button.contentEdgeInsets = UIEdgeInsetsMake( 0.0f 808 | , 5.0f 809 | , 0.0f 810 | , 5.0f); 811 | [self.button sizeToFit]; 812 | self.button.frame = CGRectMake((self.viewController.view.frame.size.width - ELEMENTS_PADDING - self.button.frame.size.width) 813 | , 0.0 814 | , self.button.frame.size.width 815 | , 32.0); 816 | if (self.userPressedButtonCallback) { 817 | [self.button addTarget:self action:@selector(userDidPressedButton:) forControlEvents:UIControlEventTouchUpInside]; 818 | } 819 | 820 | [self addSubview:self.button]; 821 | } 822 | } 823 | 824 | -(void)setupButtonAutoLayout { 825 | NSMutableDictionary *buttonAndsubTitleDictionary = (self.subTitle ? [[NSMutableDictionary alloc] 826 | initWithDictionary:NSDictionaryOfVariableBindings (_subtitleLabel, _button)] : nil); 827 | NSMutableDictionary *buttonAndTitleDictionary = (self.titleBanner ? [[NSMutableDictionary alloc] initWithDictionary:NSDictionaryOfVariableBindings (_button, _titleLabel)] : nil); 828 | 829 | [self addConstraint: 830 | [NSLayoutConstraint constraintWithItem:self 831 | attribute:NSLayoutAttributeCenterY 832 | relatedBy:NSLayoutRelationEqual 833 | toItem:_button 834 | attribute:NSLayoutAttributeCenterY 835 | multiplier:1.0f 836 | constant:0.0f]]; 837 | 838 | 839 | NSString* leftRightConstraintsVisualFormat = [NSString stringWithFormat:@"H:[_titleLabel]-==%f-[_button]-==%f-|" 840 | , ELEMENTS_PADDING 841 | , ELEMENTS_PADDING]; 842 | [self addConstraints: 843 | [NSLayoutConstraint constraintsWithVisualFormat:leftRightConstraintsVisualFormat 844 | options:0 845 | metrics:nil 846 | views:buttonAndTitleDictionary]]; 847 | if (buttonAndsubTitleDictionary) { 848 | [self addConstraints: 849 | [NSLayoutConstraint constraintsWithVisualFormat: 850 | [NSString stringWithFormat:@"H:[_subtitleLabel]-==%f-[_button]-==%f-|" 851 | , ELEMENTS_PADDING 852 | , ELEMENTS_PADDING] 853 | options:0 854 | metrics:nil 855 | views:buttonAndsubTitleDictionary]]; 856 | } 857 | 858 | NSString *widthButtonFormat = [NSString stringWithFormat:@"[_button(==%f)]", 859 | _button.frame.size.width]; 860 | [self addConstraints: 861 | [NSLayoutConstraint constraintsWithVisualFormat:widthButtonFormat 862 | options:0 863 | metrics:nil 864 | views:NSDictionaryOfVariableBindings(_button)]]; 865 | 866 | NSString *heightButtonFormat = [NSString stringWithFormat:@"V:[_button(==%f)]", 867 | _button.frame.size.height]; 868 | [self addConstraints: 869 | [NSLayoutConstraint constraintsWithVisualFormat:heightButtonFormat 870 | options:0 871 | metrics:nil 872 | views:NSDictionaryOfVariableBindings(_button)]]; 873 | 874 | } 875 | 876 | 877 | - (void)centerButton { 878 | self.button.center = CGPointMake( self.button.center.x 879 | , ((self.messageViewHeight + ELEMENTS_PADDING) / 2.0f)); 880 | } 881 | 882 | #pragma mark - 883 | #pragma mark View Cosmetic 884 | -(NSString *)getStyleTypeLabel:(MBLMessageBannerType)bannerType { 885 | NSString* styleLabel; 886 | 887 | switch (bannerType) { 888 | case MBLMessageBannerTypeError: 889 | styleLabel = ERROR_JSON_LABEL; 890 | break; 891 | case MBLMessageBannerTypeWarning: 892 | styleLabel = WARNING_JSON_LABEL; 893 | break; 894 | case MBLMessageBannerTypeMessage: 895 | styleLabel = MESSAGE_JSON_LABEL; 896 | break; 897 | case MBLMessageBannerTypeSuccess: 898 | styleLabel = SUCCESS_JSON_LABEL; 899 | break; 900 | default: 901 | styleLabel = MESSAGE_JSON_LABEL; 902 | break; 903 | } 904 | return styleLabel; 905 | } 906 | 907 | - (void) setupStyleWithType:(MBLMessageBannerType)bannerType { 908 | [self applyMessageStyleFromDictionnary:_currentDesign]; 909 | } 910 | 911 | - (void)applyMessageStyleFromDictionnary:(NSDictionary *)messageStyle { 912 | 913 | [self setBackgroundColor:[UIColor colorWithHexString:[messageStyle objectForKey:BACKGROUND_COLOR_KEY] alpha:[[messageStyle objectForKey:BACKGROUND_ALPHA_KEY] floatValue]]]; 914 | if ([messageStyle objectForKey:BACKGROUND_IMAGE_KEY] && [UIImage imageNamed:[messageStyle objectForKey:BACKGROUND_IMAGE_KEY]]) { 915 | [self setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:[messageStyle objectForKey:BACKGROUND_IMAGE_KEY]]]]; 916 | [self setAlpha:[[messageStyle objectForKey:BACKGROUND_ALPHA_KEY] floatValue]]; 917 | } 918 | 919 | 920 | [self.titleLabel setFont:[UIFont boldSystemFontOfSize:[[messageStyle valueForKey:TITLE_TEXT_SIZE_KEY] floatValue]]]; 921 | [self.titleLabel setTextColor:[UIColor colorWithHexString:[messageStyle objectForKey:TITLE_TEXT_COLOR_KEY]]]; 922 | [self.titleLabel setShadowColor:[UIColor colorWithHexString:[messageStyle objectForKey:TITLE_TEXT_SHADOW_COLOR_KEY] alpha:[[messageStyle objectForKey:TITLE_TEXT_SHADOW_ALPHA_KEY] floatValue]]]; 923 | [self.titleLabel setShadowOffset:CGSizeMake([[messageStyle objectForKey:TITLE_TEXT_SHADOW_OFFSET_X_KEY] floatValue], 924 | [[messageStyle objectForKey: TITLE_TEXT_SHADOW_OFFSET_Y_KEY] floatValue])]; 925 | 926 | 927 | [self.subtitleLabel setFont:[UIFont systemFontOfSize:[[messageStyle valueForKey:SUBTITLE_TEXT_SIZE_KEY] floatValue]]]; 928 | [self.subtitleLabel setTextColor:[UIColor colorWithHexString:[messageStyle objectForKey:SUBTITLE_TEXT_COLOR_KEY]]]; 929 | [self.subtitleLabel setShadowColor:[UIColor colorWithHexString:[messageStyle objectForKey:SUBTITLE_TEXT_SHADOW_COLOR_KEY] alpha:[[messageStyle objectForKey:SUBTITLE_TEXT_SHADOW_ALPHA_KEY] floatValue]]]; 930 | [self.subtitleLabel setShadowOffset:CGSizeMake([[messageStyle objectForKey:SUBTITLE_TEXT_SHADOW_OFFSET_X_KEY] floatValue], 931 | [[messageStyle objectForKey:SUBTITLE_TEXT_SHADOW_OFFSET_Y_KEY] floatValue])]; 932 | 933 | 934 | 935 | [self.button setTitleColor:[UIColor colorWithHexString:[messageStyle objectForKey:BUTTON_TEXT_COLOR_KEY]] forState:UIControlStateNormal]; 936 | [self.button setTitleShadowColor:[UIColor colorWithHexString:[messageStyle objectForKey:BUTTON_TEXT_SHADOW_COLOR_KEY] alpha:[[messageStyle objectForKey:BUTTON_TEXT_SHADOW_ALPHA_KEY] floatValue]] forState:UIControlStateNormal]; 937 | [self.button.titleLabel setShadowOffset:CGSizeMake([[messageStyle objectForKey:BUTTON_TEXT_SHADOW_OFFSET_X_KEY] floatValue], 938 | [[messageStyle objectForKey:BUTTON_TEXT_SHADOW_OFFSET_Y_KEY] floatValue])]; 939 | 940 | 941 | [self.button setBackgroundColor:[UIColor colorWithHexString:[messageStyle objectForKey:BUTTON_BACKGROUND_COLOR_KEY] alpha:[[messageStyle objectForKey:BUTTON_BACKGROUND_ALPHA_KEY] floatValue]]]; 942 | 943 | if ([messageStyle objectForKey:BUTTON_BACKGROUND_IMAGE_KEY] != nil && 944 | [UIImage imageNamed:[messageStyle objectForKey:BUTTON_BACKGROUND_IMAGE_KEY]] != nil) { 945 | [self.button setBackgroundImage:[UIImage imageNamed:[messageStyle objectForKey:BUTTON_BACKGROUND_IMAGE_KEY]] forState:UIControlStateNormal]; 946 | [self.button setAlpha:[[messageStyle objectForKey:BUTTON_BACKGROUND_ALPHA_KEY] floatValue]]; 947 | } 948 | if ([messageStyle objectForKey:BUTTON_BACKGROUND_PATTERN_IMAGE_KEY] != nil && 949 | [UIImage imageNamed:[messageStyle objectForKey:BUTTON_BACKGROUND_PATTERN_IMAGE_KEY]] != nil) { 950 | [self.button setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:[messageStyle objectForKey:BUTTON_BACKGROUND_PATTERN_IMAGE_KEY]]]]; 951 | [self.button setAlpha:[[messageStyle objectForKey:BUTTON_BACKGROUND_ALPHA_KEY] floatValue]]; 952 | } 953 | [self.button.layer setCornerRadius:[[messageStyle objectForKey:BUTTON_CORNER_RADIUS_KEY] floatValue]]; 954 | [self.button.layer setMasksToBounds:YES]; 955 | 956 | [self.button.layer setBorderColor:[[UIColor colorWithHexString:[messageStyle objectForKey:BUTTON_BORDER_COLOR_KEY] alpha:[[messageStyle objectForKey:BUTTON_BORDER_ALPHA_KEY] floatValue]] CGColor]]; 957 | [self.button.layer setBorderWidth:[[messageStyle objectForKey:BUTTON_BORDER_SIZE_KEY] floatValue]]; 958 | 959 | } 960 | 961 | #pragma mark - 962 | #pragma mark Swipe Gesture Reconizer handler methods 963 | 964 | -(void)dismissViewWithGesture:(UIGestureRecognizer*)gesture { 965 | 966 | if (self.isBannerDisplayed == YES) { 967 | 968 | dispatch_async(dispatch_get_main_queue(), ^{ 969 | if (self.userDissmissedCallback) { 970 | self.userDissmissedCallback(self); 971 | } 972 | [[MBLMessageBanner sharedSingleton] hideMessageBanner:self withGesture:gesture andCompletion:nil]; 973 | }); 974 | 975 | } 976 | } 977 | 978 | #pragma mark - Button Pressed Gesture Recognizer methods 979 | 980 | - (void)userDidPressedButton:(UIButton *)sender { 981 | (void)sender; 982 | if (self.userPressedButtonCallback) { 983 | self.userPressedButtonCallback(self); 984 | } 985 | } 986 | 987 | /* 988 | // Only override drawRect: if you perform custom drawing. 989 | // An empty implementation adversely affects performance during animation. 990 | - (void)drawRect:(CGRect)rect 991 | { 992 | // Drawing code 993 | } 994 | */ 995 | 996 | @end 997 | -------------------------------------------------------------------------------- /MessageBannerDemo/.gitignore: -------------------------------------------------------------------------------- 1 | Podfile.lock 2 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 21171B1D197E09810038E717 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21171B1C197E09810038E717 /* Foundation.framework */; }; 11 | 21171B1F197E09810038E717 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21171B1E197E09810038E717 /* CoreGraphics.framework */; }; 12 | 21171B21197E09810038E717 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21171B20197E09810038E717 /* UIKit.framework */; }; 13 | 21171B27197E09810038E717 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 21171B25197E09810038E717 /* InfoPlist.strings */; }; 14 | 21171B29197E09810038E717 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 21171B28197E09810038E717 /* main.m */; }; 15 | 21171B2D197E09810038E717 /* MBDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 21171B2C197E09810038E717 /* MBDAppDelegate.m */; }; 16 | 21171B30197E09810038E717 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 21171B2E197E09810038E717 /* Main.storyboard */; }; 17 | 21171B33197E09810038E717 /* MBDViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 21171B32197E09810038E717 /* MBDViewController.m */; }; 18 | 21171B35197E09810038E717 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 21171B34197E09810038E717 /* Images.xcassets */; }; 19 | 7325D36F9669488A956EE77F /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA3EA25C42494D54BBA8E40C /* libPods.a */; }; 20 | A1690F611A08EE9200B2BEEC /* CustomBannerDesign.json in Resources */ = {isa = PBXBuildFile; fileRef = A1690F601A08EE9200B2BEEC /* CustomBannerDesign.json */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 21171B19197E09810038E717 /* MessageBannerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MessageBannerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 21171B1C197E09810038E717 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 26 | 21171B1E197E09810038E717 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 27 | 21171B20197E09810038E717 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 28 | 21171B24197E09810038E717 /* MessageBannerDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MessageBannerDemo-Info.plist"; sourceTree = ""; }; 29 | 21171B26197E09810038E717 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 30 | 21171B28197E09810038E717 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 31 | 21171B2A197E09810038E717 /* MessageBannerDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MessageBannerDemo-Prefix.pch"; sourceTree = ""; }; 32 | 21171B2B197E09810038E717 /* MBDAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBDAppDelegate.h; sourceTree = ""; }; 33 | 21171B2C197E09810038E717 /* MBDAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBDAppDelegate.m; sourceTree = ""; }; 34 | 21171B2F197E09810038E717 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 35 | 21171B31197E09810038E717 /* MBDViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBDViewController.h; sourceTree = ""; }; 36 | 21171B32197E09810038E717 /* MBDViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBDViewController.m; sourceTree = ""; }; 37 | 21171B34197E09810038E717 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 38 | 21171B3B197E09810038E717 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 39 | A1690F601A08EE9200B2BEEC /* CustomBannerDesign.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = CustomBannerDesign.json; sourceTree = ""; }; 40 | B1B70A4B38735E5AF698F0AD /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 41 | DA3EA25C42494D54BBA8E40C /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | F35A3FC638CCC82A45AC9473 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 43 | /* End PBXFileReference section */ 44 | 45 | /* Begin PBXFrameworksBuildPhase section */ 46 | 21171B16197E09810038E717 /* Frameworks */ = { 47 | isa = PBXFrameworksBuildPhase; 48 | buildActionMask = 2147483647; 49 | files = ( 50 | 21171B1F197E09810038E717 /* CoreGraphics.framework in Frameworks */, 51 | 21171B21197E09810038E717 /* UIKit.framework in Frameworks */, 52 | 21171B1D197E09810038E717 /* Foundation.framework in Frameworks */, 53 | 7325D36F9669488A956EE77F /* libPods.a in Frameworks */, 54 | ); 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | /* End PBXFrameworksBuildPhase section */ 58 | 59 | /* Begin PBXGroup section */ 60 | 21171B10197E09810038E717 = { 61 | isa = PBXGroup; 62 | children = ( 63 | 21171B22197E09810038E717 /* MessageBannerDemo */, 64 | 21171B41197E09810038E717 /* MessageBannerDemoTests */, 65 | 21171B1B197E09810038E717 /* Frameworks */, 66 | 21171B1A197E09810038E717 /* Products */, 67 | 80F3C71AA1C4B937E98878FA /* Pods */, 68 | ); 69 | sourceTree = ""; 70 | }; 71 | 21171B1A197E09810038E717 /* Products */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 21171B19197E09810038E717 /* MessageBannerDemo.app */, 75 | ); 76 | name = Products; 77 | sourceTree = ""; 78 | }; 79 | 21171B1B197E09810038E717 /* Frameworks */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 21171B1C197E09810038E717 /* Foundation.framework */, 83 | 21171B1E197E09810038E717 /* CoreGraphics.framework */, 84 | 21171B20197E09810038E717 /* UIKit.framework */, 85 | 21171B3B197E09810038E717 /* XCTest.framework */, 86 | DA3EA25C42494D54BBA8E40C /* libPods.a */, 87 | ); 88 | name = Frameworks; 89 | sourceTree = ""; 90 | }; 91 | 21171B22197E09810038E717 /* MessageBannerDemo */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | A1690F601A08EE9200B2BEEC /* CustomBannerDesign.json */, 95 | 21171B2B197E09810038E717 /* MBDAppDelegate.h */, 96 | 21171B2C197E09810038E717 /* MBDAppDelegate.m */, 97 | 21171B2E197E09810038E717 /* Main.storyboard */, 98 | 21171B31197E09810038E717 /* MBDViewController.h */, 99 | 21171B32197E09810038E717 /* MBDViewController.m */, 100 | 21171B34197E09810038E717 /* Images.xcassets */, 101 | 21171B23197E09810038E717 /* Supporting Files */, 102 | ); 103 | path = MessageBannerDemo; 104 | sourceTree = ""; 105 | }; 106 | 21171B23197E09810038E717 /* Supporting Files */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 21171B24197E09810038E717 /* MessageBannerDemo-Info.plist */, 110 | 21171B25197E09810038E717 /* InfoPlist.strings */, 111 | 21171B28197E09810038E717 /* main.m */, 112 | 21171B2A197E09810038E717 /* MessageBannerDemo-Prefix.pch */, 113 | ); 114 | name = "Supporting Files"; 115 | sourceTree = ""; 116 | }; 117 | 21171B41197E09810038E717 /* MessageBannerDemoTests */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 21171B42197E09810038E717 /* Supporting Files */, 121 | ); 122 | path = MessageBannerDemoTests; 123 | sourceTree = ""; 124 | }; 125 | 21171B42197E09810038E717 /* Supporting Files */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | ); 129 | name = "Supporting Files"; 130 | sourceTree = ""; 131 | }; 132 | 80F3C71AA1C4B937E98878FA /* Pods */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | F35A3FC638CCC82A45AC9473 /* Pods.debug.xcconfig */, 136 | B1B70A4B38735E5AF698F0AD /* Pods.release.xcconfig */, 137 | ); 138 | name = Pods; 139 | sourceTree = ""; 140 | }; 141 | /* End PBXGroup section */ 142 | 143 | /* Begin PBXNativeTarget section */ 144 | 21171B18197E09810038E717 /* MessageBannerDemo */ = { 145 | isa = PBXNativeTarget; 146 | buildConfigurationList = 21171B4B197E09810038E717 /* Build configuration list for PBXNativeTarget "MessageBannerDemo" */; 147 | buildPhases = ( 148 | AF33D1F8AFAA42AE8032C871 /* Check Pods Manifest.lock */, 149 | 21171B15197E09810038E717 /* Sources */, 150 | 21171B16197E09810038E717 /* Frameworks */, 151 | 21171B17197E09810038E717 /* Resources */, 152 | 0DCE42ACA6724FDA9D448C4E /* Copy Pods Resources */, 153 | ); 154 | buildRules = ( 155 | ); 156 | dependencies = ( 157 | ); 158 | name = MessageBannerDemo; 159 | productName = MessageBannerDemo; 160 | productReference = 21171B19197E09810038E717 /* MessageBannerDemo.app */; 161 | productType = "com.apple.product-type.application"; 162 | }; 163 | /* End PBXNativeTarget section */ 164 | 165 | /* Begin PBXProject section */ 166 | 21171B11197E09810038E717 /* Project object */ = { 167 | isa = PBXProject; 168 | attributes = { 169 | CLASSPREFIX = MBD; 170 | LastUpgradeCheck = 0510; 171 | ORGANIZATIONNAME = "Thibault Carpentier"; 172 | }; 173 | buildConfigurationList = 21171B14197E09810038E717 /* Build configuration list for PBXProject "MessageBannerDemo" */; 174 | compatibilityVersion = "Xcode 3.2"; 175 | developmentRegion = English; 176 | hasScannedForEncodings = 0; 177 | knownRegions = ( 178 | en, 179 | Base, 180 | ); 181 | mainGroup = 21171B10197E09810038E717; 182 | productRefGroup = 21171B1A197E09810038E717 /* Products */; 183 | projectDirPath = ""; 184 | projectRoot = ""; 185 | targets = ( 186 | 21171B18197E09810038E717 /* MessageBannerDemo */, 187 | ); 188 | }; 189 | /* End PBXProject section */ 190 | 191 | /* Begin PBXResourcesBuildPhase section */ 192 | 21171B17197E09810038E717 /* Resources */ = { 193 | isa = PBXResourcesBuildPhase; 194 | buildActionMask = 2147483647; 195 | files = ( 196 | 21171B35197E09810038E717 /* Images.xcassets in Resources */, 197 | 21171B27197E09810038E717 /* InfoPlist.strings in Resources */, 198 | A1690F611A08EE9200B2BEEC /* CustomBannerDesign.json in Resources */, 199 | 21171B30197E09810038E717 /* Main.storyboard in Resources */, 200 | ); 201 | runOnlyForDeploymentPostprocessing = 0; 202 | }; 203 | /* End PBXResourcesBuildPhase section */ 204 | 205 | /* Begin PBXShellScriptBuildPhase section */ 206 | 0DCE42ACA6724FDA9D448C4E /* Copy Pods Resources */ = { 207 | isa = PBXShellScriptBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | ); 211 | inputPaths = ( 212 | ); 213 | name = "Copy Pods Resources"; 214 | outputPaths = ( 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | shellPath = /bin/sh; 218 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 219 | showEnvVarsInLog = 0; 220 | }; 221 | AF33D1F8AFAA42AE8032C871 /* Check Pods Manifest.lock */ = { 222 | isa = PBXShellScriptBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | ); 226 | inputPaths = ( 227 | ); 228 | name = "Check Pods Manifest.lock"; 229 | outputPaths = ( 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | shellPath = /bin/sh; 233 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 234 | showEnvVarsInLog = 0; 235 | }; 236 | /* End PBXShellScriptBuildPhase section */ 237 | 238 | /* Begin PBXSourcesBuildPhase section */ 239 | 21171B15197E09810038E717 /* Sources */ = { 240 | isa = PBXSourcesBuildPhase; 241 | buildActionMask = 2147483647; 242 | files = ( 243 | 21171B2D197E09810038E717 /* MBDAppDelegate.m in Sources */, 244 | 21171B29197E09810038E717 /* main.m in Sources */, 245 | 21171B33197E09810038E717 /* MBDViewController.m in Sources */, 246 | ); 247 | runOnlyForDeploymentPostprocessing = 0; 248 | }; 249 | /* End PBXSourcesBuildPhase section */ 250 | 251 | /* Begin PBXVariantGroup section */ 252 | 21171B25197E09810038E717 /* InfoPlist.strings */ = { 253 | isa = PBXVariantGroup; 254 | children = ( 255 | 21171B26197E09810038E717 /* en */, 256 | ); 257 | name = InfoPlist.strings; 258 | sourceTree = ""; 259 | }; 260 | 21171B2E197E09810038E717 /* Main.storyboard */ = { 261 | isa = PBXVariantGroup; 262 | children = ( 263 | 21171B2F197E09810038E717 /* Base */, 264 | ); 265 | name = Main.storyboard; 266 | sourceTree = ""; 267 | }; 268 | /* End PBXVariantGroup section */ 269 | 270 | /* Begin XCBuildConfiguration section */ 271 | 21171B49197E09810038E717 /* Debug */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ALWAYS_SEARCH_USER_PATHS = NO; 275 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 276 | CLANG_CXX_LIBRARY = "libc++"; 277 | CLANG_ENABLE_MODULES = YES; 278 | CLANG_ENABLE_OBJC_ARC = YES; 279 | CLANG_WARN_BOOL_CONVERSION = YES; 280 | CLANG_WARN_CONSTANT_CONVERSION = YES; 281 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 282 | CLANG_WARN_EMPTY_BODY = YES; 283 | CLANG_WARN_ENUM_CONVERSION = YES; 284 | CLANG_WARN_INT_CONVERSION = YES; 285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 287 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 288 | COPY_PHASE_STRIP = NO; 289 | GCC_C_LANGUAGE_STANDARD = gnu99; 290 | GCC_DYNAMIC_NO_PIC = NO; 291 | GCC_OPTIMIZATION_LEVEL = 0; 292 | GCC_PREPROCESSOR_DEFINITIONS = ( 293 | "DEBUG=1", 294 | "$(inherited)", 295 | ); 296 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 299 | GCC_WARN_UNDECLARED_SELECTOR = YES; 300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 301 | GCC_WARN_UNUSED_FUNCTION = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 304 | ONLY_ACTIVE_ARCH = YES; 305 | SDKROOT = iphoneos; 306 | }; 307 | name = Debug; 308 | }; 309 | 21171B4A197E09810038E717 /* Release */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | ALWAYS_SEARCH_USER_PATHS = NO; 313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 314 | CLANG_CXX_LIBRARY = "libc++"; 315 | CLANG_ENABLE_MODULES = YES; 316 | CLANG_ENABLE_OBJC_ARC = YES; 317 | CLANG_WARN_BOOL_CONVERSION = YES; 318 | CLANG_WARN_CONSTANT_CONVERSION = YES; 319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 320 | CLANG_WARN_EMPTY_BODY = YES; 321 | CLANG_WARN_ENUM_CONVERSION = YES; 322 | CLANG_WARN_INT_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 325 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 326 | COPY_PHASE_STRIP = YES; 327 | ENABLE_NS_ASSERTIONS = NO; 328 | GCC_C_LANGUAGE_STANDARD = gnu99; 329 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 330 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 331 | GCC_WARN_UNDECLARED_SELECTOR = YES; 332 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 333 | GCC_WARN_UNUSED_FUNCTION = YES; 334 | GCC_WARN_UNUSED_VARIABLE = YES; 335 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 336 | SDKROOT = iphoneos; 337 | VALIDATE_PRODUCT = YES; 338 | }; 339 | name = Release; 340 | }; 341 | 21171B4C197E09810038E717 /* Debug */ = { 342 | isa = XCBuildConfiguration; 343 | baseConfigurationReference = F35A3FC638CCC82A45AC9473 /* Pods.debug.xcconfig */; 344 | buildSettings = { 345 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 346 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 347 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 348 | GCC_PREFIX_HEADER = "MessageBannerDemo/MessageBannerDemo-Prefix.pch"; 349 | INFOPLIST_FILE = "MessageBannerDemo/MessageBannerDemo-Info.plist"; 350 | PRODUCT_NAME = "$(TARGET_NAME)"; 351 | WRAPPER_EXTENSION = app; 352 | }; 353 | name = Debug; 354 | }; 355 | 21171B4D197E09810038E717 /* Release */ = { 356 | isa = XCBuildConfiguration; 357 | baseConfigurationReference = B1B70A4B38735E5AF698F0AD /* Pods.release.xcconfig */; 358 | buildSettings = { 359 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 360 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 361 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 362 | GCC_PREFIX_HEADER = "MessageBannerDemo/MessageBannerDemo-Prefix.pch"; 363 | INFOPLIST_FILE = "MessageBannerDemo/MessageBannerDemo-Info.plist"; 364 | PRODUCT_NAME = "$(TARGET_NAME)"; 365 | WRAPPER_EXTENSION = app; 366 | }; 367 | name = Release; 368 | }; 369 | /* End XCBuildConfiguration section */ 370 | 371 | /* Begin XCConfigurationList section */ 372 | 21171B14197E09810038E717 /* Build configuration list for PBXProject "MessageBannerDemo" */ = { 373 | isa = XCConfigurationList; 374 | buildConfigurations = ( 375 | 21171B49197E09810038E717 /* Debug */, 376 | 21171B4A197E09810038E717 /* Release */, 377 | ); 378 | defaultConfigurationIsVisible = 0; 379 | defaultConfigurationName = Release; 380 | }; 381 | 21171B4B197E09810038E717 /* Build configuration list for PBXNativeTarget "MessageBannerDemo" */ = { 382 | isa = XCConfigurationList; 383 | buildConfigurations = ( 384 | 21171B4C197E09810038E717 /* Debug */, 385 | 21171B4D197E09810038E717 /* Release */, 386 | ); 387 | defaultConfigurationIsVisible = 0; 388 | defaultConfigurationName = Release; 389 | }; 390 | /* End XCConfigurationList section */ 391 | }; 392 | rootObject = 21171B11197E09810038E717 /* Project object */; 393 | } 394 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 27 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 56 | 63 | 70 | 77 | 84 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 109 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/CustomBannerDesign.json: -------------------------------------------------------------------------------- 1 | { 2 | "Error": { 3 | "defaultImageForType" : "ErrorDefaultLeftImage.pngYOUWISH" 4 | 5 | ,"blurRadius" : 20.0 6 | 7 | ,"backgroundColor" : "#EC736B" 8 | ,"backgroundImageName" : "ErrorBackgroundDefaultImage.pngNO" 9 | ,"backgroundAlpha" : 0.98 10 | 11 | ,"titleTextColor" : "#97000D" 12 | ,"titleTextSize" : 14 13 | ,"titleTextShadowColor" : "#FFFFFF" 14 | ,"titleTextShadowAlpha" : 0.25 15 | ,"titleTextShadowOffsetX" : 0 16 | ,"titleTextShadowOffsetY" : 1 17 | 18 | ,"subtitleTextColor" : "#F0F0F0" 19 | ,"subtitleTextSize" : 12 20 | ,"subtitleTextShadowColor" : "#000000" 21 | ,"subtitleTextShadowAlpha" : 0.25 22 | ,"subtitleTextShadowOffsetX" : 0 23 | ,"subtitleTextShadowOffsetY" : 1 24 | 25 | ,"buttonBackgroundColor" : "#97000D" 26 | ,"buttonBackgroundImage" : "CustomBackgroundImage.pngNOT_ACTIVE" 27 | ,"buttonBackgroundPatternImage" : "CustomBackgroundPattern.pngNOT_ACTIVE" 28 | ,"buttonBackgroundAlpha" : 0.98 29 | ,"buttonCornerRadius" : 5.0 30 | ,"buttonBorderColor" : "#FFFFFF" 31 | ,"buttonBorderAlpha" : 0.75 32 | ,"buttonBorderSize" : 0.0 33 | ,"buttonTextColor" : "#F0F0F0" 34 | ,"buttonTextShadowColor" : "#000000" 35 | ,"buttonTextShadowAlpha" : 0.1 36 | ,"buttonTextShadowOffsetX" : 0 37 | ,"buttonTextShadowOffsetY" : 1 38 | }, 39 | 40 | "Warning": { 41 | "defaultImageForType" : "WarningDefaultLeftImage.png" 42 | 43 | ,"blurRadius" : 0.0 44 | 45 | ,"backgroundColor" : "#F19B2C" 46 | ,"backgroundImageName" : "WarningBackgroundDefaultImage.pngNOT" 47 | ,"backgroundAlpha" : 0.98 48 | 49 | ,"titleTextColor" : "#FDE4C6" 50 | ,"titleTextSize" : 14 51 | ,"titleTextShadowColor" : "#000000" 52 | ,"titleTextShadowAlpha" : 0.25 53 | ,"titleTextShadowOffsetX" : 0 54 | ,"titleTextShadowOffsetY" : 1 55 | 56 | ,"subtitleTextColor" : "#000000" 57 | ,"subtitleTextSize" : 12 58 | ,"subtitleTextShadowColor" : "#FFFFFF" 59 | ,"subtitleTextShadowAlpha" : 0.25 60 | ,"subtitleTextShadowOffsetX" : 0 61 | ,"subtitleTextShadowOffsetY" : 1 62 | 63 | ,"buttonBackgroundColor" : "#FDE4C6" 64 | ,"buttonBackgroundImage" : "CustomBackgroundImage.pngNOT_ACTIVE" 65 | ,"buttonBackgroundPatternImage" : "CustomBackgroundPattern.pngNOT_ACTIVE" 66 | ,"buttonBackgroundAlpha" : 0.98 67 | ,"buttonCornerRadius" : 5.0 68 | ,"buttonBorderColor" : "#FFFFFF" 69 | ,"buttonBorderAlpha" : 0.75 70 | ,"buttonBorderSize" : 0.0 71 | ,"buttonTextColor" : "#000000" 72 | ,"buttonTextShadowColor" : "#FFFFFF" 73 | ,"buttonTextShadowAlpha" : 0.1 74 | ,"buttonTextShadowOffsetX" : 0 75 | ,"buttonTextShadowOffsetY" : 1 76 | }, 77 | 78 | "Message": { 79 | "defaultImageForType" : "MessageDefaultLeftImage.png" 80 | 81 | ,"blurRadius" : 0.0 82 | 83 | ,"backgroundColor" : "#87D3F2" 84 | ,"backgroundImageName" : "MessageBackgroundDefaultImage.pngNOT_ACTIVE" 85 | ,"backgroundAlpha" : 0.98 86 | 87 | ,"titleTextColor" : "#2A7AB7" 88 | ,"titleTextSize" : 14 89 | ,"titleTextShadowColor" : "#FFFFFF" 90 | ,"titleTextShadowAlpha" : 0.25 91 | ,"titleTextShadowOffsetX" : 0 92 | ,"titleTextShadowOffsetY" : 1 93 | 94 | ,"subtitleTextColor" : "#FFFFFF" 95 | ,"subtitleTextSize" : 12 96 | ,"subtitleTextShadowColor" : "#000000" 97 | ,"subtitleTextShadowAlpha" : 0.25 98 | ,"subtitleTextShadowOffsetX" : 0 99 | ,"subtitleTextShadowOffsetY" : 1 100 | 101 | ,"buttonBackgroundColor" : "#2A7AB7" 102 | ,"buttonBackgroundImage" : "CustomBackgroundImage.pngNOT_ACTIVE" 103 | ,"buttonBackgroundPatternImage" : "CustomBackgroundPattern.pngNOT_ACTIVE" 104 | ,"buttonBackgroundAlpha" : 0.98 105 | ,"buttonCornerRadius" : 5.0 106 | ,"buttonBorderColor" : "#FFFFFF" 107 | ,"buttonBorderAlpha" : 0.75 108 | ,"buttonBorderSize" : 0.0 109 | ,"buttonTextColor" : "#FFFFFF" 110 | ,"buttonTextShadowColor" : "#000000" 111 | ,"buttonTextShadowAlpha" : 0.1 112 | ,"buttonTextShadowOffsetX" : 0 113 | ,"buttonTextShadowOffsetY" : 1 114 | }, 115 | 116 | "Success": { 117 | "defaultImageForType" : "" 118 | 119 | ,"blurRadius" : 0.0 120 | 121 | ,"backgroundColor" : "#111E8A" 122 | ,"backgroundImageName" : "" 123 | ,"backgroundAlpha" : 0.98 124 | 125 | ,"titleTextColor" : "#3BAF4A" 126 | ,"titleTextSize" : 15 127 | ,"titleTextShadowColor" : "#FFFFFF" 128 | ,"titleTextShadowAlpha" : 0.25 129 | ,"titleTextShadowOffsetX" : 0 130 | ,"titleTextShadowOffsetY" : 1 131 | 132 | ,"subtitleTextColor" : "#FFFFFF" 133 | ,"subtitleTextSize" : 12 134 | ,"subtitleTextShadowColor" : "#3BAF4A" 135 | ,"subtitleTextShadowAlpha" : 0.25 136 | ,"subtitleTextShadowOffsetX" : 0 137 | ,"subtitleTextShadowOffsetY" : 1 138 | 139 | ,"buttonBackgroundColor" : "#3BAF4A" 140 | ,"buttonBackgroundImage" : "CustomBackgroundImage.pngNOT_ACTIVE" 141 | ,"buttonBackgroundPatternImage" : "CustomBackgroundPattern.pngNOT_ACTIVE" 142 | ,"buttonBackgroundAlpha" : 0.98 143 | ,"buttonCornerRadius" : 5.0 144 | ,"buttonBorderColor" : "#FFFFFF" 145 | ,"buttonBorderAlpha" : 0.75 146 | ,"buttonBorderSize" : 0.0 147 | ,"buttonTextColor" : "#FFFFFF" 148 | ,"buttonTextShadowColor" : "#000000" 149 | ,"buttonTextShadowAlpha" : 0.1 150 | ,"buttonTextShadowOffsetX" : 0 151 | ,"buttonTextShadowOffsetY" : 1 152 | } 153 | } -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/MBDAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // MBDAppDelegate.h 3 | // MessageBannerDemo 4 | // 5 | // Created by Thibault Carpentier on 7/21/14. 6 | // Copyright (c) 2014 Thibault Carpentier. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MBDAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/MBDAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // MBDAppDelegate.m 3 | // MessageBannerDemo 4 | // 5 | // Created by Thibault Carpentier on 7/21/14. 6 | // Copyright (c) 2014 Thibault Carpentier. All rights reserved. 7 | // 8 | 9 | #import "MBDAppDelegate.h" 10 | 11 | @implementation MBDAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/MBDViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // MessageBanner 4 | // 5 | // Created by Thibault Carpentier on 4/22/14. 6 | // Copyright (c) 2014 Thibault Carpentier. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MBLMessageBanner.h" 11 | 12 | @interface ViewController : UIViewController 13 | @end 14 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/MBDViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MBLMessageBanner 4 | // 5 | // Created by Thibault Carpentier on 4/22/14. 6 | // Copyright (c) 2014 Thibault Carpentier. All rights reserved. 7 | // 8 | 9 | #import "MBDViewController.h" 10 | #import "MBLMessageBannerView.h" 11 | 12 | @interface ViewController () 13 | 14 | @property (nonatomic, assign) MBLMessageBannerPosition messagePosition; 15 | @property (nonatomic, assign) MBLMessageBannerType messageType; 16 | @property (nonatomic, copy) NSString* bannerTitle; 17 | @property (nonatomic, copy) NSString* subTitle; 18 | @property (nonatomic, copy) UIImage* image; 19 | @property (nonatomic, assign) CGFloat duration; 20 | @property (nonatomic, assign) BOOL userDismissEnabled; 21 | @property (nonatomic, copy) NSString* buttonTitle; 22 | 23 | @property (weak, nonatomic) IBOutlet UISegmentedControl* userDismissSegmentedControl; 24 | @property (weak, nonatomic) IBOutlet UISlider* durationSlider; 25 | @property (weak, nonatomic) IBOutlet UILabel* durationLabel; 26 | 27 | @end 28 | 29 | @implementation ViewController 30 | 31 | #pragma mark - Life cycle 32 | 33 | - (void)viewDidLoad 34 | { 35 | [super viewDidLoad]; 36 | self.bannerTitle = @"Small title."; 37 | self.subTitle = @"Small subtitle."; 38 | self.image = nil; 39 | self.duration = MBLMessageBannerDurationDefault; 40 | self.messageType = MBLMessageBannerTypeError; 41 | self.messagePosition = MBLMessageBannerPositionTop; 42 | self.userDismissEnabled = YES; 43 | self.buttonTitle = nil; 44 | 45 | //If you want to have a custom design file 46 | //[MBLMessageBannerView setDefaultDesignFile:@"CustomBannerDesign.json"]; 47 | 48 | [[NSNotificationCenter defaultCenter] addObserver:self 49 | selector:@selector(messageBannerViewWillAppearNotification:) 50 | name:MESSAGE_BANNER_VIEW_WILL_APPEAR_NOTIFICATION 51 | object:nil]; 52 | [[NSNotificationCenter defaultCenter] addObserver:self 53 | selector:@selector(messageBannerViewDidAppearNotification:) 54 | name:MESSAGE_BANNER_VIEW_DID_APPEAR_NOTIFICATION 55 | object:nil]; 56 | [[NSNotificationCenter defaultCenter] addObserver:self 57 | selector:@selector(messageBannerViewWillDisappearNotification:) 58 | name:MESSAGE_BANNER_VIEW_WILL_DISAPPEAR_NOTIFICATION 59 | object:nil]; 60 | [[NSNotificationCenter defaultCenter] addObserver:self 61 | selector:@selector(messageBannerViewDidDisappearNotification:) 62 | name:MESSAGE_BANNER_VIEW_DID_DISAPPEAR_NOTIFICATION 63 | object:nil]; 64 | } 65 | 66 | -(void)viewDidAppear:(BOOL)animated { 67 | } 68 | 69 | - (void)didReceiveMemoryWarning 70 | { 71 | [super didReceiveMemoryWarning]; 72 | // Dispose of any resources that can be recreated. 73 | } 74 | 75 | #pragma mark - 76 | #pragma mark Popup buttons 77 | 78 | - (IBAction)popMeOne:(id)sender { 79 | 80 | 81 | // [MBLMessageBanner setMessageBannerDelegate:self]; 82 | [MBLMessageBanner showMessageBannerInViewController:self.navigationController 83 | title:self.bannerTitle 84 | subtitle:self.subTitle 85 | image:self.image 86 | type:self.messageType 87 | duration:self.duration 88 | userDissmissedCallback:^(MBLMessageBannerView* message) { 89 | NSLog(@"Banner with :\n{\n" 90 | "Title: [%@]\n" 91 | "Subtitle: [%@]\n" 92 | "Image: [%@]\n" 93 | "Type: [%@]\n" 94 | "Duration: [%f]\n" 95 | "Position: [%@]\n" 96 | "User interaction allowed: [%@]\n" 97 | "}\n has been [DISMISSED]." 98 | , message.titleBanner 99 | , message.subTitle 100 | , (message.image ? @"Icon setted" : @"No icon setted") 101 | , [self getTypeDescription:message.bannerType] 102 | , message.duration 103 | , [self getPositionDescription:message.position] 104 | , (message.userDismissEnabled ? @"YES" : @"NO") 105 | ); 106 | 107 | return ; 108 | } 109 | buttonTitle:self.buttonTitle 110 | userPressedButtonCallback:^ (MBLMessageBannerView* banner) { 111 | 112 | [MBLMessageBanner hideMessageBannerWithCompletion:^{ 113 | NSLog(@"Dismissed"); 114 | }]; 115 | return ; 116 | } 117 | atPosition:self.messagePosition 118 | canBeDismissedByUser:self.userDismissEnabled 119 | delegate:self]; 120 | 121 | 122 | 123 | NSLog(@"Banner with :\n{\n" 124 | "Title: [%@]\n " 125 | "Subtitle: [%@]\n" 126 | "Image: [%@]\n" 127 | "Type: [%@]\n" 128 | "Duration: [%f]\n" 129 | "Position: [%@]\n" 130 | "User interaction allowed: [%@]\n" 131 | "}\n is [SHOWED]." 132 | , self.bannerTitle 133 | , self.subTitle 134 | , (self.image ? @"Icon setted." : @"No icon setted.") 135 | , [self getTypeDescription:self.messageType] 136 | , self.duration 137 | , [self getPositionDescription:self.messagePosition] 138 | , (self.userDismissEnabled ? @"YES" : @"NO") 139 | ); 140 | } 141 | 142 | #pragma mark - 143 | #pragma mark MBLMessageBanner delegate methods 144 | 145 | - (void)messageBannerViewWillAppear:(MBLMessageBannerView *)messageBanner { 146 | NSLog(@"MBLMessageBanner [WILL APPEAR]"); 147 | } 148 | 149 | - (void)messageBannerViewDidAppear:(MBLMessageBannerView *)messageBanner { 150 | NSLog(@"MBLMessageBanner [DID APPEAR]"); 151 | } 152 | 153 | - (void)messageBannerViewWillDisappear:(MBLMessageBannerView *)messageBanner { 154 | NSLog(@"MBLMessageBanner [WILL DISAPPEAR]"); 155 | } 156 | 157 | - (void)messageBannerViewDidDisappear:(MBLMessageBannerView *)messageBanner { 158 | NSLog(@"MBLMessageBanner [DID DISAPPEAR]"); 159 | } 160 | 161 | #pragma mark - 162 | #pragma mark MBLMessageBanner notification methods 163 | 164 | - (void)messageBannerViewWillAppearNotification:(MBLMessageBannerView *)messageBanner { 165 | NSLog(@"NOTIFICATION => MBLMessageBanner [WILL APPEAR]"); 166 | } 167 | 168 | - (void)messageBannerViewDidAppearNotification:(MBLMessageBannerView *)messageBanner { 169 | NSLog(@"NOTIFICATION => MBLMessageBanner [DID APPEAR]"); 170 | } 171 | 172 | - (void)messageBannerViewWillDisappearNotification:(MBLMessageBannerView *)messageBanner { 173 | NSLog(@"NOTIFICATION => MBLMessageBanner [WILL DISAPPEAR]"); 174 | } 175 | 176 | - (void)messageBannerViewDidDisappearNotification:(MBLMessageBannerView *)messageBanner { 177 | NSLog(@"NOTIFICATION => MBLMessageBanner [DID DISAPPEAR]"); 178 | } 179 | 180 | 181 | #pragma mark - 182 | #pragma mark ConvertionMethods 183 | 184 | - (NSString *)getTypeDescription:(MBLMessageBannerType)bannerType { 185 | NSString* result; 186 | 187 | switch (bannerType) { 188 | case MBLMessageBannerTypeError: { 189 | result = @"Message Banner Error"; 190 | break; 191 | } 192 | case MBLMessageBannerTypeWarning: { 193 | result = @"Message Banner Warning"; 194 | break; 195 | } 196 | case MBLMessageBannerTypeMessage: { 197 | result = @"Message Banner Message"; 198 | break; 199 | } 200 | case MBLMessageBannerTypeSuccess: { 201 | result = @"Message Banner Success"; 202 | break; 203 | } 204 | 205 | default: 206 | result = @"Unknow Message Banner type"; 207 | break; 208 | } 209 | return result; 210 | } 211 | 212 | - (NSString *)getPositionDescription:(MBLMessageBannerPosition)bannerPosition { 213 | NSString* result; 214 | switch (bannerPosition) { 215 | case MBLMessageBannerPositionBottom: { 216 | result = @"Message Banner Bottom"; 217 | break; 218 | } 219 | case MBLMessageBannerPositionCenter: { 220 | result = @"Message Banner Middle"; 221 | break; 222 | } 223 | case MBLMessageBannerPositionTop: { 224 | result = @"Message Banner Top"; 225 | break; 226 | } 227 | 228 | default: { 229 | result = @"Unknow Message Banner position"; 230 | break; 231 | } 232 | } 233 | return result; 234 | } 235 | 236 | #pragma mark - 237 | #pragma mark NavBar Buttons 238 | 239 | - (IBAction)toggleNavBar:(id)sender { 240 | self.navigationController.navigationBarHidden = !self.navigationController.navigationBarHidden; 241 | self.navigationController.toolbarHidden = !self.navigationController.toolbarHidden; 242 | } 243 | 244 | #pragma mark - 245 | #pragma mark Segmented Control Methods 246 | 247 | - (IBAction)subtitleSegmentedControlValueChanged:(UISegmentedControl *)sender { 248 | 249 | switch (sender.selectedSegmentIndex) { 250 | case 0: { 251 | self.bannerTitle = @"Small Title."; 252 | self.subTitle = @"Small subtitle."; 253 | break; 254 | } 255 | case 1: { 256 | self.bannerTitle = @"This title is a medium title, with not too much characters."; 257 | self.subTitle = @"This text is a medium subtitle, with not too much characters."; 258 | break; 259 | } 260 | case 2: { 261 | self.bannerTitle = @"This text is written to be a very long title, it has a lot of text. And everything works fine, isn't it great ?"; 262 | self.subTitle = @"This text is written to be a very long subtitle, it has a lot of text. And everything works fine, isn't it great ?"; 263 | break; 264 | } 265 | default: 266 | break; 267 | } 268 | } 269 | 270 | - (IBAction)imageSegmentedControlValueChanged:(UISegmentedControl *)sender { 271 | switch (sender.selectedSegmentIndex) { 272 | case 0: { 273 | self.image = nil; 274 | break; 275 | } 276 | case 1: { 277 | self.image = [UIImage imageNamed:@"iconTest"]; 278 | break; 279 | } 280 | default: 281 | break; 282 | } 283 | } 284 | 285 | - (IBAction)messageTypeSegmentedControlValueChanged:(UISegmentedControl *)sender { 286 | switch (sender.selectedSegmentIndex) { 287 | case 0: { 288 | self.messageType = MBLMessageBannerTypeError; 289 | break; 290 | } 291 | case 1: { 292 | self.messageType = MBLMessageBannerTypeWarning; 293 | break; 294 | } 295 | case 2: { 296 | self.messageType = MBLMessageBannerTypeMessage; 297 | break; 298 | } 299 | case 3: { 300 | self.messageType = MBLMessageBannerTypeSuccess; 301 | break; 302 | } 303 | default: 304 | break; 305 | } 306 | } 307 | 308 | - (IBAction)messagePositionSegmentedControlValueChanged:(UISegmentedControl *)sender { 309 | switch (sender.selectedSegmentIndex) { 310 | case 0: { 311 | self.messagePosition = MBLMessageBannerPositionTop; 312 | break; 313 | } 314 | case 1: { 315 | self.messagePosition = MBLMessageBannerPositionCenter; 316 | break; 317 | } 318 | case 2: { 319 | self.messagePosition = MBLMessageBannerPositionBottom; 320 | break; 321 | } 322 | default: 323 | break; 324 | } 325 | } 326 | 327 | - (IBAction)userDismissEnabledSegmentedControlChanged:(UISegmentedControl *)sender { 328 | if (sender.selectedSegmentIndex == NO && self.durationSlider.value == -1.0f) { 329 | [self.durationSlider setValue:0 animated:YES]; 330 | [self durationSliderValueChanged:self.durationSlider]; 331 | } 332 | self.userDismissEnabled = sender.selectedSegmentIndex; 333 | 334 | } 335 | 336 | - (IBAction)buttonEnabledSegmentedControlChanged:(UISegmentedControl *)sender { 337 | if (sender.selectedSegmentIndex == 0) { 338 | self.buttonTitle = nil; 339 | } else { 340 | self.buttonTitle = @"Dismiss"; 341 | } 342 | 343 | } 344 | 345 | 346 | #pragma mark - 347 | #pragma mark UISlider methods 348 | 349 | - (IBAction)durationSliderValueChanged:(UISlider *)sender { 350 | if (self.userDismissSegmentedControl.selectedSegmentIndex == NO && sender.value == -1.0f) { 351 | [self.userDismissSegmentedControl setSelectedSegmentIndex:YES]; 352 | [self userDismissEnabledSegmentedControlChanged:self.userDismissSegmentedControl]; 353 | } 354 | 355 | int rounded = sender.value; //Casting to an int will truncate, round down 356 | [sender setValue:rounded animated:NO]; 357 | 358 | switch (rounded) { 359 | case -1: { 360 | self.durationLabel.text = @"Endless"; 361 | self.duration = MBLMessageBannerDurationEndless; 362 | break; 363 | } 364 | case 0: { 365 | self.durationLabel.text = @"Automatic"; 366 | self.duration = MBLMessageBannerDurationDefault; 367 | break; 368 | } 369 | default: { 370 | self.durationLabel.text = [NSString stringWithFormat:@"%d seconds", rounded]; 371 | self.duration = rounded; 372 | break; 373 | } 374 | } 375 | } 376 | 377 | @end 378 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/MessageBannerDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | Loadex.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/MessageBannerDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /MessageBannerDemo/MessageBannerDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MessageBannerDemo 4 | // 5 | // Created by Thibault Carpentier on 7/21/14. 6 | // Copyright (c) 2014 Thibault Carpentier. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "MBDAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([MBDAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MessageBannerDemo/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform :ios, '7.0' 4 | pod 'MessageBanner', :path => '../' 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Message Banner 2 | ============== 3 | 4 | This library provides an **easy to use and fully customizable class to show notifications** views on top/bottom/center of the screen. 5 | 6 | The messages banners are regrouped in 4 different type : **Error**, **Warning**, **Message** and **Success**. 7 | 8 | Each different type of banner can have different and fully customizable appearance and behavior. (See configuration section) 9 | 10 | Each banner can show a **title**, a **subtitle**, an **image** and a **button**. 11 | 12 | ![Demo](/Screenshots/liveDemo.gif "Message Banner demo") 13 | 14 | ScreenShots 15 | ---------------- 16 | ![Error](/Screenshots/ErrorMessageBanner.png?raw=true "Standart Error message banner") 17 | ![Warning](/Screenshots/WarningMessageBanner.png?raw=true "Standart Warning message banner") 18 | ![Message](/Screenshots/MessageMessageBanner.png?raw=true "Standart Message message banner") 19 | ![Success](/Screenshots/SuccessMessageBanner.png?raw=true "Standart Success message banner") 20 | 21 | Installation 22 | ---------------- 23 | ### From CocoaPods 24 | 25 | The recommended approach for installating ```MessageBanner``` is via the [CocoaPods](http://cocoapods.org/) package manager, as it provides flexible dependency management and dead simple installation: 26 | 27 | ```bash 28 | $ [sudo] gem install cocoapods 29 | $ pod setup 30 | ``` 31 | Change to the directory of your Xcode project: 32 | 33 | ``` bash 34 | $ cd /path/to/MyProject 35 | $ touch Podfile 36 | $ edit Podfile 37 | ``` 38 | 39 | Edit your Podfile and add MessageBanner: 40 | 41 | ``` bash 42 | platform :ios, '7.0' 43 | pod 'MessageBanner', '~> 1.0' 44 | ``` 45 | 46 | Install into your Xcode project: 47 | 48 | ``` bash 49 | $ pod install 50 | ``` 51 | 52 | Open your project in Xcode from the .xcworkspace file (not the usual project file) 53 | 54 | ``` bash 55 | $ open MyProject.xcworkspace 56 | ``` 57 | 58 | Please note that if your installation fails, it may be because you are installing with a version of Git lower than CocoaPods is expecting. Please ensure that you are running Git >= **1.8.0** by executing `git --version`. You can get a full picture of the installation details by executing `pod install --verbose`. 59 | 60 | 61 | 62 | ### Manually 63 | #### Dependency : 64 | The project use [HexColors](https://github.com/mRs-/HexColors) and [FXBlurView](https://github.com/nicklockwood/FXBlurView) 65 | You need to also install them manually. Please consult their installation requirement on their github pages. 66 | 67 | #### MBLMessageBanner manual installation 68 | Download Message banner project. You can download it directly from his [github page](https://github.com/Loadex/Message-Banner) 69 | or via the command line : 70 | ``` bash 71 | $ git clone https://github.com/Loadex/Message-Banner.git 72 | ``` 73 | Drag the ```Message Banner``` folder into your project. 74 | 75 | Quick Start Guide 76 | ---------------- 77 | 78 | 79 | Add the import to the top of classes that will use it. : 80 | ```objective-c 81 | #import 82 | ``` 83 | 84 | To show a basic notification use one of the following call : 85 | ```objective-c 86 | [MBLMessageBanner showMessageBannerInViewController:aViewController 87 | title:@"aTitle" 88 | subtitle:@"aSubtitle"]; 89 | 90 | // ------------------------- OR ------------------------- 91 | 92 | [MBLMessageBanner showMessageBannerInViewController:self 93 | title:@"aTitle" 94 | subtitle:@"aSubtitle" 95 | image:[UIImage imageNamed:@"icon.png"] 96 | type:MBLMessageBannerTypeMessage 97 | duration:MBLMessageBannerDurationDefault 98 | userDissmissedCallback:^(MBLMessageBannerView *bannerView) { 99 | return; 100 | } 101 | buttonTitle:@"BtnTitile" 102 | userPressedButtonCallback:^(MBLMessageBannerView *banner) { 103 | return; 104 | } 105 | atPosition:MBLMessageBannerPositionTop 106 | canBeDismissedByUser:YES delegate:self]; 107 | 108 | ``` 109 | 110 | Class documentation 111 | ---------------- 112 | ###MBLMessageBanner class documentation 113 | The **MBLMessageBanner class** provide the following methods 114 | 115 | ```objective-c 116 | + (void)setDefaultViewController:(UIViewController *)aViewController; 117 | ``` 118 | Allow you to set a default view controller where the banners will be attached. 119 | **Default value** : UIApplication sharedApplication].keyWindow.rootViewController 120 | 121 | ```objective-c 122 | + (void)setMessageBannerDelegate:(id)aDelegate; 123 | ``` 124 | Allow to set the delegate of MBLMessageBanner class 125 | **See delegate documentation** 126 | 127 | ```objective-c 128 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 129 | title:(NSString *)title 130 | subtitle:(NSString *)subtitle; 131 | 132 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 133 | title:(NSString *)title 134 | subtitle:(NSString *)subtitle 135 | atPosition:(MBLMessageBannerPosition)messagePosition; 136 | 137 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 138 | title:(NSString *)title 139 | subtitle:(NSString *)subtitle 140 | type:(MBLMessageBannerType)type 141 | atPosition:(MBLMessageBannerPosition)messagePosition; 142 | 143 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 144 | title:(NSString *)title 145 | subtitle:(NSString *)subtitle 146 | type:(MBLMessageBannerType)type 147 | duration:(NSTimeInterval)duration 148 | atPosition:(MBLMessageBannerPosition)messagePosition; 149 | 150 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 151 | title:(NSString *)title 152 | subtitle:(NSString *)subtitle 153 | type:(MBLMessageBannerType)type 154 | duration:(NSTimeInterval)duration 155 | userDissmissedCallback:(void (^)(MBLMessageBannerView* bannerView))userDissmissedCallback 156 | atPosition:(MBLMessageBannerPosition)messagePosition 157 | canBeDismissedByUser:(BOOL)dismissingEnabled; 158 | 159 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 160 | title:(NSString *)title 161 | subtitle:(NSString *)subtitle 162 | image:(UIImage *)image 163 | type:(MBLMessageBannerType)type 164 | duration:(NSTimeInterval)duration 165 | userDissmissedCallback:(void (^)(MBLMessageBannerView* bannerView))userDissmissedCallback 166 | atPosition:(MBLMessageBannerPosition)messagePosition 167 | canBeDismissedByUser:(BOOL)dismissingEnabled; 168 | 169 | + (void)showMessageBannerInViewController:(UIViewController *)viewController 170 | title:(NSString *)title 171 | subtitle:(NSString *)subtitle 172 | image:(UIImage *)image 173 | type:(MBLMessageBannerType)type 174 | duration:(NSTimeInterval)duration 175 | userDissmissedCallback:(void (^)(MBLMessageBannerView* bannerView))userDissmissedCallback 176 | buttonTitle:(NSString *)buttonTitle 177 | userPressedButtonCallback:(void (^)(MBLMessageBannerView* banner))userPressedButtonCallback 178 | atPosition:(MBLMessageBannerPosition)messagePosition 179 | canBeDismissedByUser:(BOOL)dismissingEnabled 180 | delegate:(id )aDelegate; 181 | 182 | 183 | + (void)showMessageBanner:(MBLMessageBannerView *)messageBannerView; 184 | ``` 185 | Add a new MBLMessageBannerView to be displayed. Each MBLMessageBannerView is shown on the screen alone. If multiple calls, the MBLMessageBanner will show it when the previous message banner views disappeared. 186 | **Parameters description** 187 | * **viewController**: The view controller to show the message banner in. Can also be a UINavigationController. If nil, will use the default view controller instead. 188 | * **title**: The title in the message banner view. 189 | * **subtitle**: The subtitle in the message banner view. 190 | * **image**: The left image showed in the message banner view. 191 | * **type**: The message banner view type (See type section for available values). The message type allow to load the correct design in the design configuration file. (See configuration file section) 192 | * **duration**: The message banner displaying duration in seconds. (See duration section for custom values) 193 | * **userDissmissedCallback**: The block that should be executed when a user dismiss a message banner. (see dismiss gestures section to see possible dismiss gestures) 194 | * **buttonTittle**: The title of the button. If set will allow a button to be created otherwise the message banner won't have a button. 195 | * **userPressedButtonCallback**: The block that should be executed when a user hit the button if not nil. 196 | * **messagePosition**: The message position on the viewController. (see position section to see possible positions) 197 | * **dismissingEnabled**: Enable or disable the user dismissing methods on the message banner view. 198 | * **aDelegate**: Set the delegate of the message banner (See delegate documentation to see available delegate methods) 199 | * **messageBannerView**: An existing instance of a MessageBannerView to show next or instantly in not any are showed. 200 | 201 | ```objective-c 202 | + (BOOL) hideMessageBanner; 203 | + (BOOL) hideMessageBannerWithCompletion:(void (^)())completion; 204 | ``` 205 | Hide the currently displayed message banner 206 | **Parameters description** 207 | * **completion**: The block that should be executed when the message banner is hidden. 208 | **Return value** 209 | * **BOOL**: Return YES if a message banner has been dismissed, NO otherwise. 210 | 211 | ###MBLMessageBannerView class documentation 212 | The **MBLMessageBannerView** class provide the following methods: 213 | ```objective-c 214 | + (BOOL)addMessageBannerDesignFromFileNamed:(NSString *)file; 215 | ``` 216 | Load a custom message banner design file. 217 | **Parameters description** 218 | * **file**:The name of the JSON config file. (See design configuration file section for syntax) 219 | **Return value**: YES if the file is corretly loaded. NO otherwise. 220 | 221 | Delegate methods 222 | ---------------- 223 | The message banner class implements a delegate protocol with the following **optional** methods: 224 | ```objective-c 225 | - (void)messageBannerViewWillAppear:(MBLMessageBannerView *)messageBanner; 226 | - (void)messageBannerViewDidAppear:(MBLMessageBannerView *)messageBanner; 227 | - (void)messageBannerViewWillDisappear:(MBLMessageBannerView *)messageBanner; 228 | - (void)messageBannerViewDidDisappear:(MBLMessageBannerView *)messageBanner; 229 | ``` 230 | **Parameters description** 231 | * messageBanner The message banner about to be displayed/hidden 232 | 233 | NSNotifications 234 | ---------------- 235 | The MBLMessageBanner class also send signals when the message banner is about or did appear/disappear. Each notification is directly **sent by the MBLMessageBannerView**. 236 | The signals sent are: 237 | 238 | 239 | |Description |Notification name |Notification define | 240 | |:----------------------------------------:|:----------------------------------------:|:---------------------------------------------:| 241 | |Sent when the view is about to appear. |messageBannerViewWillAppearNotification |MESSAGE_BANNER_VIEW_WILL_APPEAR_NOTIFICATION | 242 | |Sent when the view is about to appear. |messageBannerViewDidAppearNotification |MESSAGE_BANNER_VIEW_DID_APPEAR_NOTIFICATION | 243 | |Sent when the view is about to disappear. |messageBannerViewWillDisappearNotification|MESSAGE_BANNER_VIEW_WILL_DISAPPEAR_NOTIFICATION| 244 | |Sent when the view is about to disappear. |messageBannerViewDidDisappearNotification |MESSAGE_BANNER_VIEW_DID_DISAPPEAR_NOTIFICATION | 245 | 246 | Message Positions 247 | ----------------- 248 | Each Message Banner View has a position. By default or if not set, the message banner view will have the position defined by **MBLMessageBannerPositionTop** 249 | Available positions are: 250 | * **MBLMessageBannerPositionTop**: The message banner will be displayed on the top of the view controller, right under the status bar or the navigation controller if the view has one. 251 | * **MBLMessageBannerPositionCenter**: The message banner will be displayed on the middle of the view controller. 252 | * **MBLMessageBannerPositionBottom**: The message banner will be displayed on the bottom of the view controller, or just above the toolbar if the view has one. 253 | ![Top Positionning](/Screenshots/MessageBannerTopPosition.png?raw=true "Top positioned message banner") 254 | ![Center Positioning](/Screenshots/MessageBannerMiddlePosition.png?raw=true "Centered message banner") 255 | ![Bottom Positioning](/Screenshots/MessageBannerBottomPosition.png?raw=true "Bottom positioned message banner") 256 | 257 | Message types 258 | ---------------- 259 | Each Message Banner is defined by his type. The desig in the config file is loaded according to the his type. 260 | Available type with their already setted design are : 261 | * **MBLMessageBannerTypeError**: The error message banner. 262 | * **MBLMessageBannerTypeWarning**: The warning message banner. 263 | * **MBLMessageBannerTypeMessage**: The standart message banner. 264 | * **MBLMessageBannerTypeSuccess**: The success message banner. 265 | ![Message Error](/Screenshots/MessageBannerErrorType.png?raw=true "Error message banner") 266 | ![Message Warning](/Screenshots/MessageBannerWarningType.png?raw=true "Warning message banner") 267 | ![Message](/Screenshots/MessageBannerMessageType.png?raw=true "Message message banner") 268 | ![Message Success](/Screenshots/MessageBannerSuccessType.png?raw=true "Success message banner") 269 | 270 | Message duration 271 | ---------------- 272 | Each Message Banner has a "stay on screen" time. This duration can be manually setted by the method parameter. However, the class also provide custom durations : 273 | * **MBLMessageBannerDurationDefault**: The duration will be automatically calculated according to the size of the message banner view. 274 | * **MBLMessageBannerDurationEndless**: The message banner will be displayed until the user dismiss it or it is dismissed programatically. 275 | 276 | Dismiss methods 277 | ---------------- 278 | The message banner can be dismissed with multiple user gesture. The user can dismiss it with a **single tap** on the view and swipes gesture. The swipes dismiss gesture are different according to the position of the banner. 279 | * **MBLMessageBannerPositionTop**: The user can **swipe to the top** of the screen to dismiss the banner. 280 | * **MBLMessageBannerPositionCenter**: The user can **swipe both to the left and right** to dismiss the banner. 281 | * **MBLMessageBannerPositionBottom**: The user can **swipe to the bottom** of the screen to dismiss the banner. 282 | 283 | Design configuration file 284 | ---------------- 285 | The configuration file is a JSON formated file. 286 | 287 | The JSON file is formatted this way : 288 | 289 | ```JSON 290 | { 291 | "MessageBannerTypeName": { 292 | "PropertyName" : "Property value" 293 | ,"AnotherProperty" : 1.0 294 | }, 295 | 296 | "AnOtherMessageBannerTypeName": { 297 | "PropertyName" : "Property value" 298 | ,"AnotherProperty" : 1.0 299 | } 300 | } 301 | ``` 302 | 303 | This library come with 4 differents type of banner, with the following corresponding name for the JSON design file format : 304 | 305 | | Name | Type | 306 | |:--------:|:--------:| 307 | |Error |MBLMessageBannerTypeError| 308 | |Warning |MBLMessageBannerTypeWarning| 309 | |Message |MBLMessageBannerTypeMessage| 310 | |Success |MBLMessageBannerTypeSuccess| 311 | 312 | Each type of banner can have the following properties : 313 | 314 | ### General properties 315 | | Property name | Effect | Possible values | Default value | Remarks | 316 | |:---------------------:|---------------------------------------------|:--------------------:|:------------------:|-------------------------------------------| 317 | |defaultImageForType | Define a default left image | "The_image_name.png" | None |The image parameter override this setting | 318 | |blurRadius | Blur the attached view with the given radius| 0.0+ | 0.0 (Disabled) | iOS7 style default radius for blur is 40.0| 319 | |backgroundColor | Set the banner background color | "#FFFFFF" | "#FFFFFF" (White) | BackgroundImageName override this parameter| 320 | |backgroundImageName | Set the banner background image | "The_image_name.png" | None | Override BackgroundColor property | 321 | |backgroundAlpha | Set the banner background color transparency| 0.0 -> 1.0 | 1.0 | | 322 | 323 | ### Title properties 324 | | Property name | Effect | Possible values | Default value | Remarks | 325 | |:---------------------:|---------------------------------------------|:--------------------:|:------------------:|-------------------------------------------| 326 | |titleTextColor | Set the banner title text color | "#FFFFFF" | "#000000" (Black) | | 327 | |titleTextSize | Set the banner title text size | 0.0+ | 14.0 | | 328 | |titleTextShadowColor | Set the banner title text shadow color | "#FFFFFF" | "#FFFFFF" (White) | | 329 | |titleTextShadowAlpha | Set the banner title text shadow transparency| 0.0 -> 1.0 | 1.0 | | 330 | |titleTextShadowOffsetX | Set the banner title text x shadow offset | -0.0+ | 0.0 | | 331 | |titleTextShadowOffsetY | Set the banner title text y shadow offset | -0.0+ | 1.0 | | 332 | 333 | ### Subtitle properties 334 | | Property name | Effect | Possible values | Default value | Remarks | 335 | |:---------------------:|---------------------------------------------|:--------------------:|:------------------:|-------------------------------------------| 336 | |subtitleTextColor | Set the banner subtitle text color | "#FFFFFF" | "#000000" (Black) | | 337 | |subtitleTextSize | Set the banner subtitle text size | 0.0+ | 14.0 | | 338 | |subtitleTextShadowColor | Set the banner subtitle text shadow color | "#FFFFFF" | "#FFFFFF" (White) | | 339 | |subtitleTextShadowAlpha | Set the banner subtitle text shadow transparency| 0.0 -> 1.0 | 1.0 | | 340 | |subtitleTextShadowOffsetX | Set the banner subtitle text x shadow offset | -0.0+ | 0.0 | | 341 | |subtitleTextShadowOffsetY | Set the banner subtitle text y shadow offset | -0.0+ | 1.0 | | 342 | 343 | ### Button properties 344 | | Property name | Effect | Possible values | Default value | Remarks | 345 | |:---------------------:|---------------------------------------------|:--------------------:|:------------------:|-------------------------------------------| 346 | |buttonBackgroundColor | Set the button background color | "#FFFFFF" | "#FFFFFF" (White) | buttonBackgroundImage and buttonBackgroundPatternImage override this parameter| 347 | |buttonBackgroundImage | Set the button background image | "The_image_name.png"| None | Ovveride buttonBackgroundColor | 348 | |buttonBackgroundPatternImage | Set the button background image with a pattern image | "The_image_name.png"| None | Ovveride buttonBackgroundImage | 349 | |buttonBackgroundAlpha | Set the button background transparency | 0.0 -> 1.0 | 1.0 | | 350 | |buttonCornerRadius | Set the button corner radius | 0.0+ | 0.0 | | 351 | |buttonBorderColor | Set the button border color | "#FFFFFF" | "#000000"(Black) | Visible only if buttonBorderSize >= 1 | 352 | |buttonBorderAlpha | Set the button border transparency | 0.0 -> 1.0 | 1.0 | | 353 | |buttonBorderSize | Set the border size of the button | 0.0+ | 0.0 (None) | | 354 | |buttonTextColor | Set the banner button text color | "#FFFFFF" | "#000000" (Black) | | 355 | |buttonTextSize | Set the banner button text size | 0.0+ | 14.0 | | 356 | |buttonTextShadowColor | Set the banner button text shadow color | "#FFFFFF" | "#FFFFFF" (White) | | 357 | |buttonTextShadowAlpha | Set the banner button text shadow transparency| 0.0 -> 1.0 | 1.0 | | 358 | |buttonTextShadowOffsetX | Set the banner button text x shadow offset | -0.0+ | 0.0 | | 359 | |buttonTextShadowOffsetY | Set the banner button text y shadow offset | -0.0+ | 1.0 | | 360 | 361 | Roadmap 362 | ---------------- 363 | ####Current Version : ***1.0.3*** 364 | 365 | - ***V1.0:*** 366 | + Eventual bug fixes 367 | + Finish Readme.md documentation 368 | + Fix incorrect project organisation 369 | + Create Pod Module 370 | 371 | - ***V1.1:*** 372 | + Create JSON View Behavior Config File 373 | - Create Config for custom dismiss methods 374 | - Create config for custom animation times 375 | - Create config for custom stay in screen time automatic mode calculation 376 | - Add default image enabled or not 377 | 378 | - ***V1.2:*** 379 | + Create Manager JSON config File 380 | - Create config for multipopups (then to move in behavior cfg to separate for each type) 381 | - Create config to add “shadow” or “blur” on given View Controller (Or view on screen if its a navigation controller) 382 | - Create config to allow or not user interaction on the presented view (then to move in behavior cfg to separate for each type) 383 | - Create Auto depop when screen change var 384 | - ***V1.3:*** 385 | - Add auto-Banner for Network problem + config 386 | 387 | - ***V2.0:*** 388 | - Create Swift Version 389 | 390 | FAQ 391 | ---------------- 392 | No question asked so far. 393 | 394 | Requirements 395 | ---------------- 396 | This project require : 397 | + ```iOS7``` 398 | + ```ARC``` 399 | 400 | Licence 401 | ---------------- 402 | MIT Licence 403 | Copyright (c) 2014 Thibault Carpentier 404 | 405 | Permission is hereby granted, free of charge, to any person obtaining a copy 406 | of this software and associated documentation files (the "Software"), to deal 407 | in the Software without restriction, including without limitation the rights 408 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 409 | copies of the Software, and to permit persons to whom the Software is 410 | furnished to do so, subject to the following conditions: 411 | 412 | The above copyright notice and this permission notice shall be included in 413 | all copies or substantial portions of the Software. 414 | 415 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 416 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 417 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 418 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 419 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 420 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 421 | THE SOFTWARE. 422 | 423 | 424 | Repository Infos 425 | ---------------- 426 | 427 | Owner: Thibault Carpentier 428 | GitHub: https://github.com/Loadex 429 | LinkedIn: www.linkedin.com/in/CarpentierThibault/ 430 | StackOverflow: http://stackoverflow.com/users/1324369/loadex 431 | -------------------------------------------------------------------------------- /Screenshots/ErrorMessageBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/ErrorMessageBanner.png -------------------------------------------------------------------------------- /Screenshots/MessageBannerBottomPosition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/MessageBannerBottomPosition.png -------------------------------------------------------------------------------- /Screenshots/MessageBannerErrorType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/MessageBannerErrorType.png -------------------------------------------------------------------------------- /Screenshots/MessageBannerMessageType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/MessageBannerMessageType.png -------------------------------------------------------------------------------- /Screenshots/MessageBannerMiddlePosition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/MessageBannerMiddlePosition.png -------------------------------------------------------------------------------- /Screenshots/MessageBannerSuccessType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/MessageBannerSuccessType.png -------------------------------------------------------------------------------- /Screenshots/MessageBannerTopPosition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/MessageBannerTopPosition.png -------------------------------------------------------------------------------- /Screenshots/MessageBannerWarningType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/MessageBannerWarningType.png -------------------------------------------------------------------------------- /Screenshots/MessageMessageBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/MessageMessageBanner.png -------------------------------------------------------------------------------- /Screenshots/SuccessMessageBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/SuccessMessageBanner.png -------------------------------------------------------------------------------- /Screenshots/WarningMessageBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/WarningMessageBanner.png -------------------------------------------------------------------------------- /Screenshots/liveDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thibault-carpentier/MessageBanner/0d3ad0c4108b028725baacba2ea38be616f7b79a/Screenshots/liveDemo.gif --------------------------------------------------------------------------------