├── .gitignore ├── CSNotificationView.podspec ├── CSNotificationView ├── CSLayerStealingBlurView.h ├── CSLayerStealingBlurView.m ├── CSNativeBlurView.h ├── CSNativeBlurView.m ├── CSNotificationView.h ├── CSNotificationView.m ├── CSNotificationView_Private.h └── Resources │ ├── checkmark.png │ ├── checkmark@2x.png │ ├── checkmark@3x.png │ ├── exclamationMark.png │ ├── exclamationMark@2x.png │ └── exclamationMark@3x.png ├── Example ├── CSNotificationViewDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── CSNotificationViewDemo.xcworkspace │ └── contents.xcworkspacedata ├── CSNotificationViewDemo │ ├── CSAppDelegate.h │ ├── CSAppDelegate.m │ ├── CSDetailsViewController.h │ ├── CSDetailsViewController.m │ ├── CSNotificationViewDemo-Info.plist │ ├── CSNotificationViewDemo-Prefix.pch │ ├── CSRootViewController.h │ ├── CSRootViewController.m │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── Storyboard.storyboard │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m ├── Podfile └── Podfile.lock ├── Icons ├── checkmark.pxm └── exclamation_mark.pxm ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *~.nib 4 | 5 | build/ 6 | 7 | *.pbxuser 8 | *.perspective 9 | *.perspectivev3 10 | 11 | *.mode1v3 12 | *.mode2v3 13 | 14 | Documentation/Generated 15 | doxygenWarnings.txt 16 | *.xcuserdatad 17 | *.xcuserdatad 18 | *.xccheckout 19 | 20 | Pods/ -------------------------------------------------------------------------------- /CSNotificationView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'CSNotificationView' 3 | s.version = '0.5.4' 4 | s.summary = "Drop-in, semi-translucent and blurring notification view." 5 | s.homepage = "https://github.com/problame/CSNotificationView" 6 | s.license = { :type => 'MIT License', :file => "LICENSE.md" } 7 | s.author = 'Christian Schwarz' 8 | s.source = { :git => 'https://github.com/problame/CSNotificationView.git', :tag => s.version.to_s } 9 | s.platform = :ios 10 | s.ios.deployment_target = "7.0" 11 | s.requires_arc = true 12 | s.source_files = 'CSNotificationView/*.{h,m}' 13 | s.resource_bundle = { 'CSNotificationView' => ['CSNotificationView/Resources/*.png'] } 14 | end 15 | -------------------------------------------------------------------------------- /CSNotificationView/CSLayerStealingBlurView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSLayerStealingBlurView.h 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 23.08.14. 6 | // Copyright (c) 2014 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import 10 | #import "CSNotificationView_Private.h" 11 | 12 | @interface CSLayerStealingBlurView : UIView 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /CSNotificationView/CSLayerStealingBlurView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSLayerStealingBlurView.m 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 23.08.14. 6 | // Copyright (c) 2014 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import "CSLayerStealingBlurView.h" 10 | 11 | @interface CSLayerStealingBlurView () 12 | 13 | #pragma mark - blur effect 14 | @property (nonatomic, strong) UIToolbar *toolbar; 15 | @property (nonatomic, strong) CALayer *blurLayer; 16 | 17 | @end 18 | 19 | @implementation CSLayerStealingBlurView 20 | 21 | - (instancetype)initWithFrame:(CGRect)frame 22 | { 23 | self = [super initWithFrame:frame]; 24 | if (self) { 25 | 26 | //Thanks to https://github.com/JagCesar/iOS-blur for providing this under the WTFPL-license! 27 | 28 | self.toolbar = [[UIToolbar alloc] initWithFrame:[self toolbarFrame]]; 29 | self.blurLayer = self.toolbar.layer; 30 | 31 | self.userInteractionEnabled = NO; 32 | [self.layer addSublayer:self.blurLayer]; 33 | 34 | } 35 | return self; 36 | } 37 | 38 | - (void)setFrame:(CGRect)frame 39 | { 40 | [super setFrame:frame]; 41 | 42 | //Update blur layer frame by updating the bounds frame 43 | self.toolbar.frame = [self toolbarFrame]; 44 | 45 | } 46 | 47 | - (void)layoutSubviews 48 | { 49 | [super layoutSubviews]; 50 | self.toolbar.frame = [self toolbarFrame]; 51 | } 52 | 53 | - (CGRect)toolbarFrame 54 | { 55 | return CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)); 56 | } 57 | 58 | - (void)setBlurTintColor:(UIColor *)tintColor 59 | { 60 | NSParameterAssert(tintColor); 61 | self.toolbar.barTintColor = [tintColor colorWithAlphaComponent:0.6]; 62 | } 63 | 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /CSNotificationView/CSNativeBlurView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSNativeBlurView.h 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 23.08.14. 6 | // Copyright (c) 2014 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import 10 | #import "CSNotificationView_Private.h" 11 | 12 | @interface CSNativeBlurView : UIVisualEffectView 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /CSNotificationView/CSNativeBlurView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSNativeBlurView.m 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 23.08.14. 6 | // Copyright (c) 2014 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import "CSNativeBlurView.h" 10 | 11 | @interface CSNativeBlurView () 12 | 13 | /** 14 | A view that is used for 'injecting' the tint color 15 | The results look nicer than setting self.backgroundColor directly. 16 | */ 17 | @property (nonatomic, strong) UIView* tintColorView; 18 | 19 | @end 20 | 21 | @implementation CSNativeBlurView 22 | 23 | - (instancetype)initWithFrame:(CGRect)frame 24 | { 25 | self = [super initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; 26 | if (self) { 27 | self.tintColorView = [[UIView alloc] initWithFrame:self.bounds]; 28 | self.tintColorView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 29 | [self.contentView addSubview:self.tintColorView]; 30 | } 31 | return self; 32 | } 33 | 34 | - (void)setBlurTintColor:(UIColor *)tintColor 35 | { 36 | self.tintColorView.backgroundColor = [tintColor colorWithAlphaComponent:0.6]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /CSNotificationView/CSNotificationView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSNotificationView.h 3 | // CSNotificationView 4 | // 5 | // Created by Christian Schwarz on 01.09.13. 6 | // Copyright (c) 2013 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import 10 | 11 | static CGFloat const kCSNotificationViewHeight = 50.0f; 12 | static CGFloat const kCSNotificationViewSymbolViewSidelength = 44.0f; 13 | static NSTimeInterval const kCSNotificationViewDefaultShowDuration = 2.0; 14 | 15 | typedef NS_ENUM(NSInteger, CSNotificationViewStyle) { 16 | CSNotificationViewStyleSuccess, 17 | CSNotificationViewStyleError 18 | }; 19 | 20 | typedef void(^CSVoidBlock)(); 21 | 22 | @interface CSNotificationView : UIView 23 | 24 | #pragma mark + quick presentation 25 | 26 | + (void)showInViewController:(UIViewController*)viewController 27 | style:(CSNotificationViewStyle)style 28 | message:(NSString*)message; 29 | 30 | + (void)showInViewController:(UIViewController*)viewController 31 | tintColor:(UIColor*)tintColor 32 | image:(UIImage*)image 33 | message:(NSString*)message 34 | duration:(NSTimeInterval)duration; 35 | 36 | + (void)showInViewController:(UIViewController*)viewController 37 | tintColor:(UIColor*)tintColor 38 | font:(UIFont*)font 39 | textAlignment:(NSTextAlignment)textAlignment 40 | image:(UIImage*)image 41 | message:(NSString*)message 42 | duration:(NSTimeInterval)duration; 43 | 44 | #pragma mark + creators 45 | 46 | + (CSNotificationView*)notificationViewWithParentViewController:(UIViewController*)viewController 47 | tintColor:(UIColor*)tintColor 48 | image:(UIImage*)image 49 | message:(NSString*)message; 50 | 51 | #pragma mark + icons 52 | 53 | /** 54 | * @return The included images that are used for the `image` property when creating a notification with `style`. 55 | */ 56 | + (UIImage*)imageForStyle:(CSNotificationViewStyle)style; 57 | 58 | #pragma mark - initialization 59 | 60 | /** 61 | * Why initialize with the view controller? 62 | * CSNotificationView stays visible if `viewController` is pushed off the UINavigationController stack. 63 | * Furthermore, presentation in a UITableViewController is not possible so CSNotificationView uses 64 | * the parent view controller's view for presentation. 65 | * @param viewController The view controller in which the notification shall be presented. 66 | */ 67 | - (instancetype)initWithParentViewController:(UIViewController*)viewController NS_DESIGNATED_INITIALIZER; 68 | 69 | #pragma mark - presentation 70 | 71 | /** 72 | * @param showing Should the notification view be visible? 73 | * @param animated Should a change in `showing` be animated? 74 | * @param completion `nil` or a callback called on the main thread after changes to the interface are completed. 75 | */ 76 | - (void)setVisible:(BOOL)showing animated:(BOOL)animated completion:(void (^)())completion; 77 | 78 | /** 79 | * Convenience method to dismiss with a(nother) predefined style and / or message. 80 | */ 81 | - (void)dismissWithStyle:(CSNotificationViewStyle)style message:(NSString*)message duration:(NSTimeInterval)duration animated:(BOOL)animated; 82 | 83 | @property (readonly, nonatomic, getter = isShowing) BOOL visible; 84 | 85 | #pragma mark - visible properties 86 | 87 | /** 88 | * The image displayed as an icon on the left side of `textLabel`. 89 | * Only the alpha value will be used and then be tinted to a 'legible' color. 90 | */ 91 | @property (nonatomic, strong) UIImage* image; 92 | 93 | /** 94 | * The tint applied to the blurred background. 95 | * Note that `textLabel.textColor` is adjusted to make `textLabel` legible on the tinted background. 96 | */ 97 | @property (nonatomic, strong) UIColor* tintColor; 98 | 99 | /** 100 | * The label containing the message displayed to the user. 101 | */ 102 | @property (nonatomic, readonly) UILabel* textLabel; 103 | 104 | @property (nonatomic, getter = isShowingActivity) BOOL showingActivity; 105 | 106 | /** 107 | * A callback called if the user taps on the notification. 108 | */ 109 | @property (nonatomic, copy) CSVoidBlock tapHandler; 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /CSNotificationView/CSNotificationView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSNotificationView.m 3 | // CSNotificationView 4 | // 5 | // Created by Christian Schwarz on 01.09.13. 6 | // Copyright (c) 2013 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import "CSNotificationView.h" 10 | #import "CSNotificationView_Private.h" 11 | 12 | #import "CSLayerStealingBlurView.h" 13 | #import "CSNativeBlurView.h" 14 | 15 | @implementation CSNotificationView 16 | 17 | #pragma mark + quick presentation 18 | 19 | + (void)showInViewController:(UIViewController*)viewController 20 | tintColor:(UIColor*)tintColor 21 | image:(UIImage*)image 22 | message:(NSString*)message 23 | duration:(NSTimeInterval)duration 24 | { 25 | NSAssert(message, @"'message' must not be nil."); 26 | 27 | __block CSNotificationView* note = [[CSNotificationView alloc] initWithParentViewController:viewController]; 28 | note.tintColor = tintColor; 29 | note.image = image; 30 | note.textLabel.text = message; 31 | 32 | void (^completion)() = ^{[note setVisible:NO animated:YES completion:nil];}; 33 | [note setVisible:YES animated:YES completion:^{ 34 | double delayInSeconds = duration; 35 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 36 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 37 | completion(); 38 | }); 39 | }]; 40 | 41 | } 42 | 43 | + (void)showInViewController:(UIViewController*)viewController 44 | tintColor:(UIColor*)tintColor 45 | font:(UIFont*)font 46 | textAlignment:(NSTextAlignment)textAlignment 47 | image:(UIImage*)image 48 | message:(NSString*)message 49 | duration:(NSTimeInterval)duration 50 | { 51 | NSAssert(message, @"'message' must not be nil."); 52 | 53 | __block CSNotificationView* note = [[CSNotificationView alloc] initWithParentViewController:viewController]; 54 | note.tintColor = tintColor; 55 | note.image = image; 56 | note.textLabel.font = font; 57 | note.textLabel.textAlignment = textAlignment; 58 | note.textLabel.text = message; 59 | 60 | void (^completion)() = ^{[note setVisible:NO animated:YES completion:nil];}; 61 | [note setVisible:YES animated:YES completion:^{ 62 | double delayInSeconds = duration; 63 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 64 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 65 | completion(); 66 | }); 67 | }]; 68 | 69 | } 70 | 71 | + (void)showInViewController:(UIViewController *)viewController 72 | style:(CSNotificationViewStyle)style 73 | message:(NSString *)message 74 | { 75 | 76 | 77 | [CSNotificationView showInViewController:viewController 78 | tintColor:[CSNotificationView blurTintColorForStyle:style] 79 | image:[CSNotificationView imageForStyle:style] 80 | message:message 81 | duration:kCSNotificationViewDefaultShowDuration]; 82 | } 83 | 84 | #pragma mark + creators 85 | 86 | + (CSNotificationView*)notificationViewWithParentViewController:(UIViewController*)viewController 87 | tintColor:(UIColor*)tintColor 88 | image:(UIImage*)image 89 | message:(NSString*)message 90 | { 91 | NSParameterAssert(viewController); 92 | 93 | CSNotificationView* note = [[CSNotificationView alloc] initWithParentViewController:viewController]; 94 | note.tintColor = tintColor; 95 | note.image = image; 96 | note.textLabel.text = message; 97 | 98 | return note; 99 | } 100 | 101 | #pragma mark - lifecycle 102 | 103 | - (instancetype)initWithParentViewController:(UIViewController*)viewController 104 | { 105 | self = [super initWithFrame:CGRectZero]; 106 | if (self) { 107 | 108 | self.backgroundColor = [UIColor clearColor]; 109 | 110 | //Blur view 111 | { 112 | 113 | if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) { 114 | //Use native effects 115 | self.blurView = [[CSNativeBlurView alloc] initWithFrame:CGRectZero]; 116 | } else { 117 | //Use layer stealing 118 | self.blurView = [[CSLayerStealingBlurView alloc] initWithFrame:CGRectZero]; 119 | } 120 | 121 | self.blurView.userInteractionEnabled = NO; 122 | self.blurView.translatesAutoresizingMaskIntoConstraints = NO; 123 | self.blurView.clipsToBounds = NO; 124 | [self insertSubview:self.blurView atIndex:0]; 125 | 126 | } 127 | 128 | //Parent view 129 | { 130 | self.parentViewController = viewController; 131 | 132 | NSAssert(!([self.parentViewController isKindOfClass:[UITableViewController class]] && !self.parentViewController.navigationController), @"Due to a bug in iOS 7.0.1|2|3 UITableViewController, CSNotificationView cannot present in UITableViewController without a parent UINavigationController"); 133 | 134 | if (self.parentViewController.navigationController) { 135 | self.parentNavigationController = self.parentViewController.navigationController; 136 | } 137 | if ([self.parentViewController isKindOfClass:[UINavigationController class]]) { 138 | self.parentNavigationController = (UINavigationController*)self.parentViewController; 139 | } 140 | 141 | } 142 | 143 | //Notifications 144 | { 145 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(navigationControllerWillShowViewControllerNotification:) name:kCSNotificationViewUINavigationControllerWillShowViewControllerNotification object:nil]; 146 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(navigationControllerDidShowViewControllerNotification:) name:kCSNotificationViewUINavigationControllerDidShowViewControllerNotification object:nil]; 147 | } 148 | 149 | //Key-Value Observing 150 | { 151 | [self addObserver:self forKeyPath:kCSNavigationBarBoundsKeyPath options:NSKeyValueObservingOptionNew context:kCSNavigationBarObservationContext]; 152 | } 153 | 154 | //Content views 155 | { 156 | //textLabel 157 | { 158 | _textLabel = [[UILabel alloc] init]; 159 | 160 | _textLabel.textColor = [UIColor whiteColor]; 161 | _textLabel.backgroundColor = [UIColor clearColor]; 162 | _textLabel.translatesAutoresizingMaskIntoConstraints = NO; 163 | 164 | _textLabel.numberOfLines = 2; 165 | _textLabel.minimumScaleFactor = 0.6; 166 | _textLabel.lineBreakMode = NSLineBreakByTruncatingTail; 167 | 168 | UIFontDescriptor* textLabelFontDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody]; 169 | _textLabel.font = [UIFont fontWithDescriptor:textLabelFontDescriptor size:17.0f]; 170 | _textLabel.adjustsFontSizeToFitWidth = YES; 171 | 172 | [self addSubview:_textLabel]; 173 | } 174 | //symbolView 175 | { 176 | [self updateSymbolView]; 177 | } 178 | } 179 | 180 | //Interaction 181 | { 182 | //Tap gesture 183 | self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapInView:)]; 184 | [self addGestureRecognizer:self.tapRecognizer]; 185 | } 186 | 187 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; 188 | 189 | } 190 | return self; 191 | } 192 | 193 | - (void)dealloc 194 | { 195 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 196 | [self removeObserver:self forKeyPath:kCSNavigationBarBoundsKeyPath context:kCSNavigationBarObservationContext]; 197 | } 198 | 199 | - (void)navigationControllerWillShowViewControllerNotification:(NSNotification*)note 200 | { 201 | if (self.visible && [self.parentNavigationController isEqual:note.object]) { 202 | 203 | __block typeof(self) weakself = self; 204 | [UIView animateWithDuration:0.1 animations:^{ 205 | CGRect endFrame; 206 | [weakself animationFramesForVisible:weakself.visible startFrame:nil endFrame:&endFrame]; 207 | [weakself setFrame:endFrame]; 208 | [weakself updateConstraints]; 209 | }]; 210 | 211 | } 212 | } 213 | 214 | - (void)navigationControllerDidShowViewControllerNotification:(NSNotification*)note 215 | { 216 | if (self.visible && [self.parentNavigationController.navigationController isEqual:note.object]) { 217 | 218 | //We're about to be pushed away! This might happen in a UISplitViewController with both master/detailViewControllers being UINavgiationControllers 219 | //Move to new parent 220 | 221 | __block typeof(self) weakself = self; 222 | [self setVisible:NO animated:NO completion:^{ 223 | weakself.parentNavigationController = note.object; 224 | [weakself setVisible:YES animated:NO completion:nil]; 225 | }]; 226 | 227 | } 228 | } 229 | 230 | #pragma mark - Key-Value Observing 231 | 232 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 233 | { 234 | if (context == kCSNavigationBarObservationContext && [keyPath isEqualToString:kCSNavigationBarBoundsKeyPath]) { 235 | self.frame = self.visible ? [self visibleFrame] : [self hiddenFrame]; 236 | [self setNeedsLayout]; 237 | } else { 238 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 239 | } 240 | } 241 | 242 | #pragma mark - layout 243 | 244 | - (void)updateConstraints 245 | { 246 | [self removeConstraints:self.constraints]; 247 | 248 | NSDictionary* bindings = @{@"blurView":self.blurView}; 249 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[blurView]|" 250 | options:0 metrics:nil views:bindings]]; 251 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(-1)-[blurView]-(-1)-|" 252 | options:0 metrics:nil views:bindings]]; 253 | 254 | 255 | CGFloat symbolViewWidth = self.symbolView.tag != kCSNotificationViewEmptySymbolViewTag ? 256 | kCSNotificationViewSymbolViewSidelength : 0.0f; 257 | CGFloat symbolViewHeight = kCSNotificationViewSymbolViewSidelength; 258 | 259 | NSDictionary* metrics = 260 | @{@"symbolViewWidth": [NSNumber numberWithFloat:symbolViewWidth], 261 | @"symbolViewHeight":[NSNumber numberWithFloat:symbolViewHeight]}; 262 | 263 | [self addConstraints:[NSLayoutConstraint 264 | constraintsWithVisualFormat:@"H:|-(4)-[_symbolView(symbolViewWidth)]-(5)-[_textLabel]-(10)-|" 265 | options:0 266 | metrics:metrics 267 | views:NSDictionaryOfVariableBindings(_textLabel, _symbolView)]]; 268 | 269 | [self addConstraints:[NSLayoutConstraint 270 | constraintsWithVisualFormat:@"V:[_symbolView(symbolViewHeight)]" 271 | options:0 272 | metrics:metrics 273 | views:NSDictionaryOfVariableBindings(_symbolView)]]; 274 | 275 | [self addConstraint:[NSLayoutConstraint 276 | constraintWithItem:_symbolView 277 | attribute:NSLayoutAttributeBottom 278 | relatedBy:NSLayoutRelationEqual 279 | toItem:self 280 | attribute:NSLayoutAttributeBottom 281 | multiplier:1.0f constant:-3]]; 282 | 283 | [self addConstraint:[NSLayoutConstraint 284 | constraintWithItem:_textLabel 285 | attribute:NSLayoutAttributeCenterY 286 | relatedBy:NSLayoutRelationEqual 287 | toItem:_symbolView 288 | attribute:NSLayoutAttributeCenterY 289 | multiplier:1.0f constant:0]]; 290 | 291 | [super updateConstraints]; 292 | } 293 | 294 | #pragma mark - tint color 295 | 296 | - (void)setTintColor:(UIColor *)tintColor 297 | { 298 | _tintColor = tintColor; 299 | [self.blurView setBlurTintColor:tintColor]; 300 | self.contentColor = [self legibleTextColorForBlurTintColor:tintColor]; 301 | } 302 | 303 | #pragma mark - interaction 304 | 305 | -(void)handleTapInView:(UITapGestureRecognizer*)tapGestureRecognizer 306 | { 307 | if (self.tapHandler && tapGestureRecognizer.state == UIGestureRecognizerStateEnded) { 308 | self.tapHandler(); 309 | } 310 | } 311 | 312 | #pragma mark - presentation 313 | 314 | - (void)setVisible:(BOOL)visible animated:(BOOL)animated completion:(void (^)())completion 315 | { 316 | if (_visible != visible) { 317 | 318 | NSTimeInterval animationDuration = animated ? 0.4 : 0.0; 319 | 320 | CGRect startFrame, endFrame; 321 | [self animationFramesForVisible:visible startFrame:&startFrame endFrame:&endFrame]; 322 | 323 | if (!self.superview) { 324 | self.frame = startFrame; 325 | 326 | if (self.parentNavigationController) { 327 | [self.parentNavigationController.view insertSubview:self belowSubview:self.parentNavigationController.navigationBar]; 328 | } else { 329 | [self.parentViewController.view addSubview:self]; 330 | } 331 | 332 | } 333 | 334 | __block typeof(self) weakself = self; 335 | [UIView animateWithDuration:animationDuration animations:^{ 336 | [weakself setFrame:endFrame]; 337 | } completion:^(BOOL finished) { 338 | 339 | if (!visible) { 340 | [weakself removeFromSuperview]; 341 | } 342 | if (completion) { 343 | completion(); 344 | } 345 | }]; 346 | 347 | _visible = visible; 348 | } else if (completion) { 349 | completion(); 350 | } 351 | } 352 | 353 | - (void)animationFramesForVisible:(BOOL)visible startFrame:(CGRect*)startFrame endFrame:(CGRect*)endFrame 354 | { 355 | if (startFrame) *startFrame = visible ? [self hiddenFrame]:[self visibleFrame]; 356 | if (endFrame) *endFrame = visible ? [self visibleFrame] : [self hiddenFrame]; 357 | } 358 | 359 | - (void)dismissWithStyle:(CSNotificationViewStyle)style message:(NSString *)message duration:(NSTimeInterval)duration animated:(BOOL)animated 360 | { 361 | NSParameterAssert(message); 362 | 363 | __block typeof(self) weakself = self; 364 | [UIView animateWithDuration:0.1 animations:^{ 365 | 366 | weakself.showingActivity = NO; 367 | weakself.image = [CSNotificationView imageForStyle:style]; 368 | weakself.textLabel.text = message; 369 | weakself.tintColor = [CSNotificationView blurTintColorForStyle:style]; 370 | 371 | } completion:^(BOOL finished) { 372 | double delayInSeconds = 2.0; 373 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 374 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 375 | [weakself setVisible:NO animated:animated completion:nil]; 376 | }); 377 | }]; 378 | } 379 | 380 | #pragma mark - frame calculation 381 | 382 | //Workaround as there is a bug: sometimes, when accessing topLayoutGuide, it will render contentSize of UITableViewControllers to be {0, 0} 383 | - (CGFloat)topLayoutGuideLengthCalculation 384 | { 385 | CGFloat top = MIN([UIApplication sharedApplication].statusBarFrame.size.height, [UIApplication sharedApplication].statusBarFrame.size.width); 386 | 387 | if (self.parentNavigationController && !self.parentNavigationController.navigationBarHidden) { 388 | 389 | top += CGRectGetHeight(self.parentNavigationController.navigationBar.frame); 390 | } 391 | 392 | return top; 393 | } 394 | 395 | - (CGRect)visibleFrame 396 | { 397 | UIViewController* viewController = self.parentNavigationController ?: self.parentViewController; 398 | 399 | if (!viewController.isViewLoaded) { 400 | return CGRectZero; 401 | } 402 | 403 | CGFloat topLayoutGuideLength = [self topLayoutGuideLengthCalculation]; 404 | 405 | CGSize transformedSize = CGSizeApplyAffineTransform(viewController.view.frame.size, viewController.view.transform); 406 | CGRect displayFrame = CGRectMake(0, 0, fabs(transformedSize.width), 407 | kCSNotificationViewHeight + topLayoutGuideLength); 408 | 409 | return displayFrame; 410 | } 411 | 412 | - (CGRect)hiddenFrame 413 | { 414 | UIViewController* viewController = self.parentNavigationController ?: self.parentViewController; 415 | 416 | if (!viewController.isViewLoaded) { 417 | return CGRectZero; 418 | } 419 | 420 | CGFloat topLayoutGuideLength = [self topLayoutGuideLengthCalculation]; 421 | 422 | CGSize transformedSize = CGSizeApplyAffineTransform(viewController.view.frame.size, viewController.view.transform); 423 | CGRect offscreenFrame = CGRectMake(0, -kCSNotificationViewHeight - topLayoutGuideLength, 424 | fabs(transformedSize.width), 425 | kCSNotificationViewHeight + topLayoutGuideLength); 426 | 427 | return offscreenFrame; 428 | } 429 | 430 | - (CGSize)intrinsicContentSize 431 | { 432 | CGRect currentRect = self.visible ? [self visibleFrame] : [self hiddenFrame]; 433 | return currentRect.size; 434 | } 435 | 436 | #pragma mark - symbol view 437 | 438 | - (void)updateSymbolView 439 | { 440 | [self.symbolView removeFromSuperview]; 441 | 442 | if (self.isShowingActivity) { 443 | UIActivityIndicatorView* indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 444 | indicator.color = self.contentColor; 445 | [indicator startAnimating]; 446 | _symbolView = indicator; 447 | } else if (self.image) { 448 | //Generate UIImageView for symbolView 449 | UIImageView* imageView = [[UIImageView alloc] init]; 450 | imageView.opaque = NO; 451 | imageView.backgroundColor = [UIColor clearColor]; 452 | imageView.translatesAutoresizingMaskIntoConstraints = NO; 453 | imageView.contentMode = UIViewContentModeCenter; 454 | imageView.image = [self imageFromAlphaChannelOfImage:self.image replacementColor:self.contentColor]; 455 | _symbolView = imageView; 456 | } else { 457 | _symbolView = [[UIView alloc] initWithFrame:CGRectZero]; 458 | _symbolView.tag = kCSNotificationViewEmptySymbolViewTag; 459 | } 460 | _symbolView.translatesAutoresizingMaskIntoConstraints = NO; 461 | [self addSubview:_symbolView]; 462 | [self setNeedsUpdateConstraints]; 463 | 464 | } 465 | 466 | #pragma mark -- image 467 | 468 | - (void)setImage:(UIImage *)image 469 | { 470 | if (![_image isEqual:image]) { 471 | _image = image; 472 | [self updateSymbolView]; 473 | } 474 | } 475 | 476 | #pragma mark -- activity 477 | 478 | - (void)setShowingActivity:(BOOL)showingActivity 479 | { 480 | if (_showingActivity != showingActivity) { 481 | _showingActivity = showingActivity; 482 | [self updateSymbolView]; 483 | } 484 | } 485 | 486 | 487 | #pragma mark - content color 488 | 489 | - (void)setContentColor:(UIColor *)contentColor 490 | { 491 | if (![_contentColor isEqual:contentColor]) { 492 | _contentColor = contentColor; 493 | self.textLabel.textColor = _contentColor; 494 | [self updateSymbolView]; 495 | } 496 | } 497 | 498 | #pragma mark helpers 499 | 500 | - (UIColor*)legibleTextColorForBlurTintColor:(UIColor*)blurTintColor 501 | { 502 | CGFloat r, g, b, a; 503 | BOOL couldConvert = [blurTintColor getRed:&r green:&g blue:&b alpha:&a]; 504 | 505 | UIColor* textColor = [UIColor whiteColor]; 506 | 507 | CGFloat average = (r+g+b)/3.0; //Not considering alpha here, transperency is added by toolbar 508 | if (couldConvert && average > 0.65) //0.65 is mostly gut-feeling 509 | { 510 | textColor = [[UIColor alloc] initWithWhite:0.2 alpha:1.0]; 511 | } 512 | 513 | return textColor; 514 | } 515 | 516 | - (UIImage*)imageFromAlphaChannelOfImage:(UIImage*)image replacementColor:(UIColor*)tintColor 517 | { 518 | if (!image) return nil; 519 | NSParameterAssert([tintColor isKindOfClass:[UIColor class]]); 520 | 521 | //Credits: https://gist.github.com/omz/1102091 522 | CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); 523 | UIGraphicsBeginImageContextWithOptions(rect.size, NO, image.scale); 524 | CGContextRef c = UIGraphicsGetCurrentContext(); 525 | [image drawInRect:rect]; 526 | CGContextSetFillColorWithColor(c, [tintColor CGColor]); 527 | CGContextSetBlendMode(c, kCGBlendModeSourceAtop); 528 | CGContextFillRect(c, rect); 529 | UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); 530 | UIGraphicsEndImageContext(); 531 | return result; 532 | } 533 | 534 | + (UIImage*)imageForStyle:(CSNotificationViewStyle)style 535 | { 536 | UIImage* matchedImage = nil; 537 | 538 | // Either main bundle or framework bundle. 539 | NSBundle *containerBundle = [NSBundle bundleForClass:CSNotificationView.class]; 540 | 541 | // CSNotificationView.bundle is generated by CocoaPods using `resource_bundle` in Podspec. 542 | NSBundle *assetsBundle = [NSBundle bundleWithURL:[containerBundle URLForResource:@"CSNotificationView" withExtension:@"bundle"]]; 543 | 544 | switch (style) { 545 | case CSNotificationViewStyleSuccess: 546 | matchedImage = [UIImage imageWithContentsOfFile:[assetsBundle pathForResource:@"checkmark" ofType:@"png"]]; 547 | break; 548 | case CSNotificationViewStyleError: 549 | matchedImage = [UIImage imageWithContentsOfFile:[assetsBundle pathForResource:@"exclamationMark" ofType:@"png"]]; 550 | break; 551 | default: 552 | break; 553 | } 554 | return matchedImage; 555 | } 556 | 557 | + (UIColor*)blurTintColorForStyle:(CSNotificationViewStyle)style 558 | { 559 | UIColor* blurTintColor; 560 | switch (style) { 561 | case CSNotificationViewStyleSuccess: 562 | blurTintColor = [UIColor colorWithRed:0.21 green:0.72 blue:0.00 alpha:1.0]; 563 | break; 564 | case CSNotificationViewStyleError: 565 | blurTintColor = [UIColor redColor]; 566 | break; 567 | default: 568 | break; 569 | } 570 | return blurTintColor; 571 | } 572 | 573 | @end 574 | -------------------------------------------------------------------------------- /CSNotificationView/CSNotificationView_Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSNotificationView_Private.h 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 23.08.14. 6 | // Copyright (c) 2014 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import "CSNotificationView.h" 10 | 11 | static NSInteger const kCSNotificationViewEmptySymbolViewTag = 666; 12 | 13 | static NSString* const kCSNotificationViewUINavigationControllerWillShowViewControllerNotification = @"UINavigationControllerWillShowViewControllerNotification"; 14 | static NSString* const kCSNotificationViewUINavigationControllerDidShowViewControllerNotification = @"UINavigationControllerDidShowViewControllerNotification"; 15 | 16 | static void * kCSNavigationBarObservationContext = &kCSNavigationBarObservationContext; 17 | static NSString * kCSNavigationBarBoundsKeyPath = @"parentNavigationController.navigationBar.bounds"; 18 | 19 | @protocol CSNotificationViewBlurViewProtocol 20 | 21 | ///The tint of the blur view 22 | - (void)setBlurTintColor:(UIColor*)tintColor; 23 | 24 | @end 25 | 26 | @interface CSNotificationView () 27 | 28 | #pragma mark - blur view 29 | @property (nonatomic) UIView* blurView; 30 | 31 | #pragma mark - presentation 32 | @property (nonatomic, weak) UIViewController* parentViewController; 33 | @property (nonatomic, strong) UINavigationController* parentNavigationController; //Has to be strong-referenced because CSNotificationView does KVO on parentNavigationController 34 | @property (nonatomic, getter = isVisible) BOOL visible; 35 | 36 | #pragma mark - content views 37 | @property (nonatomic, strong, readonly) UIView* symbolView; // is updated by -(void)updateSymbolView 38 | @property (nonatomic, strong) UILabel* textLabel; 39 | @property (nonatomic, strong) UIColor* contentColor; 40 | 41 | #pragma mark - interaction 42 | @property (nonatomic, strong) UITapGestureRecognizer* tapRecognizer; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /CSNotificationView/Resources/checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/problame/CSNotificationView/37c9091f255d1f8da1a4354c8260037d708a9fab/CSNotificationView/Resources/checkmark.png -------------------------------------------------------------------------------- /CSNotificationView/Resources/checkmark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/problame/CSNotificationView/37c9091f255d1f8da1a4354c8260037d708a9fab/CSNotificationView/Resources/checkmark@2x.png -------------------------------------------------------------------------------- /CSNotificationView/Resources/checkmark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/problame/CSNotificationView/37c9091f255d1f8da1a4354c8260037d708a9fab/CSNotificationView/Resources/checkmark@3x.png -------------------------------------------------------------------------------- /CSNotificationView/Resources/exclamationMark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/problame/CSNotificationView/37c9091f255d1f8da1a4354c8260037d708a9fab/CSNotificationView/Resources/exclamationMark.png -------------------------------------------------------------------------------- /CSNotificationView/Resources/exclamationMark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/problame/CSNotificationView/37c9091f255d1f8da1a4354c8260037d708a9fab/CSNotificationView/Resources/exclamationMark@2x.png -------------------------------------------------------------------------------- /CSNotificationView/Resources/exclamationMark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/problame/CSNotificationView/37c9091f255d1f8da1a4354c8260037d708a9fab/CSNotificationView/Resources/exclamationMark@3x.png -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8E310C7918BBA9AE0081DEC7 /* CSDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E310C7818BBA9AE0081DEC7 /* CSDetailsViewController.m */; }; 11 | 8E4E1AB317D35355005EB12B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E4E1AB217D35355005EB12B /* Foundation.framework */; }; 12 | 8E4E1AB517D35355005EB12B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E4E1AB417D35355005EB12B /* CoreGraphics.framework */; }; 13 | 8E4E1AB717D35355005EB12B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E4E1AB617D35355005EB12B /* UIKit.framework */; }; 14 | 8E4E1ABD17D35355005EB12B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8E4E1ABB17D35355005EB12B /* InfoPlist.strings */; }; 15 | 8E4E1ABF17D35355005EB12B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E4E1ABE17D35355005EB12B /* main.m */; }; 16 | 8E4E1AC317D35355005EB12B /* CSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E4E1AC217D35355005EB12B /* CSAppDelegate.m */; }; 17 | 8E4E1AE717D353F3005EB12B /* CSRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E4E1AE617D353F3005EB12B /* CSRootViewController.m */; }; 18 | 8E4E1AEF17D35DBD005EB12B /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8E4E1AE117D35364005EB12B /* Storyboard.storyboard */; }; 19 | 8E757B5117D38F6B0088845B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8E757B4F17D38CE80088845B /* Images.xcassets */; }; 20 | CDA22641FF7B56FDE45B7458 /* libPods-CSNotificationViewDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D0093830E592DC8633F4507F /* libPods-CSNotificationViewDemo.a */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 880664D9E4CB6491EE4E5E3C /* Pods-CSNotificationViewDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CSNotificationViewDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CSNotificationViewDemo/Pods-CSNotificationViewDemo.debug.xcconfig"; sourceTree = ""; }; 25 | 8E310C7718BBA9AE0081DEC7 /* CSDetailsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSDetailsViewController.h; sourceTree = ""; }; 26 | 8E310C7818BBA9AE0081DEC7 /* CSDetailsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSDetailsViewController.m; sourceTree = ""; }; 27 | 8E4E1AAF17D35355005EB12B /* CSNotificationViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CSNotificationViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 8E4E1AB217D35355005EB12B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 29 | 8E4E1AB417D35355005EB12B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 30 | 8E4E1AB617D35355005EB12B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 31 | 8E4E1ABA17D35355005EB12B /* CSNotificationViewDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CSNotificationViewDemo-Info.plist"; sourceTree = ""; }; 32 | 8E4E1ABC17D35355005EB12B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 33 | 8E4E1ABE17D35355005EB12B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 34 | 8E4E1AC017D35355005EB12B /* CSNotificationViewDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CSNotificationViewDemo-Prefix.pch"; sourceTree = ""; }; 35 | 8E4E1AC117D35355005EB12B /* CSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSAppDelegate.h; sourceTree = ""; }; 36 | 8E4E1AC217D35355005EB12B /* CSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CSAppDelegate.m; sourceTree = ""; }; 37 | 8E4E1ACB17D35355005EB12B /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 38 | 8E4E1AE117D35364005EB12B /* Storyboard.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = ""; }; 39 | 8E4E1AE517D353F3005EB12B /* CSRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSRootViewController.h; sourceTree = ""; }; 40 | 8E4E1AE617D353F3005EB12B /* CSRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSRootViewController.m; sourceTree = ""; }; 41 | 8E757B4F17D38CE80088845B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 42 | 9A4F14863F8ED23637102486 /* Pods-CSNotificationViewDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CSNotificationViewDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-CSNotificationViewDemo/Pods-CSNotificationViewDemo.release.xcconfig"; sourceTree = ""; }; 43 | D0093830E592DC8633F4507F /* libPods-CSNotificationViewDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CSNotificationViewDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | /* End PBXFileReference section */ 45 | 46 | /* Begin PBXFrameworksBuildPhase section */ 47 | 8E4E1AAC17D35355005EB12B /* Frameworks */ = { 48 | isa = PBXFrameworksBuildPhase; 49 | buildActionMask = 2147483647; 50 | files = ( 51 | 8E4E1AB517D35355005EB12B /* CoreGraphics.framework in Frameworks */, 52 | 8E4E1AB717D35355005EB12B /* UIKit.framework in Frameworks */, 53 | 8E4E1AB317D35355005EB12B /* Foundation.framework in Frameworks */, 54 | CDA22641FF7B56FDE45B7458 /* libPods-CSNotificationViewDemo.a in Frameworks */, 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | 8E4E1AA617D35355005EB12B = { 62 | isa = PBXGroup; 63 | children = ( 64 | 8E4E1AB817D35355005EB12B /* CSNotificationViewDemo */, 65 | 8E4E1AB117D35355005EB12B /* Frameworks */, 66 | 8E4E1AB017D35355005EB12B /* Products */, 67 | 97AFF85B5E6D9E5841F97E5B /* Pods */, 68 | ); 69 | sourceTree = ""; 70 | }; 71 | 8E4E1AB017D35355005EB12B /* Products */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 8E4E1AAF17D35355005EB12B /* CSNotificationViewDemo.app */, 75 | ); 76 | name = Products; 77 | sourceTree = ""; 78 | }; 79 | 8E4E1AB117D35355005EB12B /* Frameworks */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 8E4E1AB217D35355005EB12B /* Foundation.framework */, 83 | 8E4E1AB417D35355005EB12B /* CoreGraphics.framework */, 84 | 8E4E1AB617D35355005EB12B /* UIKit.framework */, 85 | 8E4E1ACB17D35355005EB12B /* XCTest.framework */, 86 | D0093830E592DC8633F4507F /* libPods-CSNotificationViewDemo.a */, 87 | ); 88 | name = Frameworks; 89 | sourceTree = ""; 90 | }; 91 | 8E4E1AB817D35355005EB12B /* CSNotificationViewDemo */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 8E4E1AC117D35355005EB12B /* CSAppDelegate.h */, 95 | 8E4E1AC217D35355005EB12B /* CSAppDelegate.m */, 96 | 8E4E1AE517D353F3005EB12B /* CSRootViewController.h */, 97 | 8E4E1AE617D353F3005EB12B /* CSRootViewController.m */, 98 | 8E4E1AE117D35364005EB12B /* Storyboard.storyboard */, 99 | 8E310C7718BBA9AE0081DEC7 /* CSDetailsViewController.h */, 100 | 8E310C7818BBA9AE0081DEC7 /* CSDetailsViewController.m */, 101 | 8E757B4F17D38CE80088845B /* Images.xcassets */, 102 | 8E4E1AB917D35355005EB12B /* Supporting Files */, 103 | ); 104 | path = CSNotificationViewDemo; 105 | sourceTree = ""; 106 | }; 107 | 8E4E1AB917D35355005EB12B /* Supporting Files */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 8E4E1ABA17D35355005EB12B /* CSNotificationViewDemo-Info.plist */, 111 | 8E4E1ABB17D35355005EB12B /* InfoPlist.strings */, 112 | 8E4E1ABE17D35355005EB12B /* main.m */, 113 | 8E4E1AC017D35355005EB12B /* CSNotificationViewDemo-Prefix.pch */, 114 | ); 115 | name = "Supporting Files"; 116 | sourceTree = ""; 117 | }; 118 | 97AFF85B5E6D9E5841F97E5B /* Pods */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 880664D9E4CB6491EE4E5E3C /* Pods-CSNotificationViewDemo.debug.xcconfig */, 122 | 9A4F14863F8ED23637102486 /* Pods-CSNotificationViewDemo.release.xcconfig */, 123 | ); 124 | name = Pods; 125 | sourceTree = ""; 126 | }; 127 | /* End PBXGroup section */ 128 | 129 | /* Begin PBXNativeTarget section */ 130 | 8E4E1AAE17D35355005EB12B /* CSNotificationViewDemo */ = { 131 | isa = PBXNativeTarget; 132 | buildConfigurationList = 8E4E1ADB17D35355005EB12B /* Build configuration list for PBXNativeTarget "CSNotificationViewDemo" */; 133 | buildPhases = ( 134 | 00883B70016F4060A1A950ED /* Check Pods Manifest.lock */, 135 | 8E4E1AAB17D35355005EB12B /* Sources */, 136 | 8E4E1AAC17D35355005EB12B /* Frameworks */, 137 | 8E4E1AAD17D35355005EB12B /* Resources */, 138 | 19CFEDDF4B6643CB830EB555 /* Copy Pods Resources */, 139 | ); 140 | buildRules = ( 141 | ); 142 | dependencies = ( 143 | ); 144 | name = CSNotificationViewDemo; 145 | productName = 7Tests; 146 | productReference = 8E4E1AAF17D35355005EB12B /* CSNotificationViewDemo.app */; 147 | productType = "com.apple.product-type.application"; 148 | }; 149 | /* End PBXNativeTarget section */ 150 | 151 | /* Begin PBXProject section */ 152 | 8E4E1AA717D35355005EB12B /* Project object */ = { 153 | isa = PBXProject; 154 | attributes = { 155 | CLASSPREFIX = CS; 156 | LastUpgradeCheck = 0500; 157 | ORGANIZATIONNAME = "Christian Schwarz"; 158 | }; 159 | buildConfigurationList = 8E4E1AAA17D35355005EB12B /* Build configuration list for PBXProject "CSNotificationViewDemo" */; 160 | compatibilityVersion = "Xcode 3.2"; 161 | developmentRegion = English; 162 | hasScannedForEncodings = 0; 163 | knownRegions = ( 164 | en, 165 | ); 166 | mainGroup = 8E4E1AA617D35355005EB12B; 167 | productRefGroup = 8E4E1AB017D35355005EB12B /* Products */; 168 | projectDirPath = ""; 169 | projectRoot = ""; 170 | targets = ( 171 | 8E4E1AAE17D35355005EB12B /* CSNotificationViewDemo */, 172 | ); 173 | }; 174 | /* End PBXProject section */ 175 | 176 | /* Begin PBXResourcesBuildPhase section */ 177 | 8E4E1AAD17D35355005EB12B /* Resources */ = { 178 | isa = PBXResourcesBuildPhase; 179 | buildActionMask = 2147483647; 180 | files = ( 181 | 8E757B5117D38F6B0088845B /* Images.xcassets in Resources */, 182 | 8E4E1ABD17D35355005EB12B /* InfoPlist.strings in Resources */, 183 | 8E4E1AEF17D35DBD005EB12B /* Storyboard.storyboard in Resources */, 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXResourcesBuildPhase section */ 188 | 189 | /* Begin PBXShellScriptBuildPhase section */ 190 | 00883B70016F4060A1A950ED /* Check Pods Manifest.lock */ = { 191 | isa = PBXShellScriptBuildPhase; 192 | buildActionMask = 2147483647; 193 | files = ( 194 | ); 195 | inputPaths = ( 196 | ); 197 | name = "Check Pods Manifest.lock"; 198 | outputPaths = ( 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | shellPath = /bin/sh; 202 | 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"; 203 | showEnvVarsInLog = 0; 204 | }; 205 | 19CFEDDF4B6643CB830EB555 /* Copy Pods Resources */ = { 206 | isa = PBXShellScriptBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | ); 210 | inputPaths = ( 211 | ); 212 | name = "Copy Pods Resources"; 213 | outputPaths = ( 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | shellPath = /bin/sh; 217 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CSNotificationViewDemo/Pods-CSNotificationViewDemo-resources.sh\"\n"; 218 | showEnvVarsInLog = 0; 219 | }; 220 | /* End PBXShellScriptBuildPhase section */ 221 | 222 | /* Begin PBXSourcesBuildPhase section */ 223 | 8E4E1AAB17D35355005EB12B /* Sources */ = { 224 | isa = PBXSourcesBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | 8E4E1AE717D353F3005EB12B /* CSRootViewController.m in Sources */, 228 | 8E4E1AC317D35355005EB12B /* CSAppDelegate.m in Sources */, 229 | 8E4E1ABF17D35355005EB12B /* main.m in Sources */, 230 | 8E310C7918BBA9AE0081DEC7 /* CSDetailsViewController.m in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXSourcesBuildPhase section */ 235 | 236 | /* Begin PBXVariantGroup section */ 237 | 8E4E1ABB17D35355005EB12B /* InfoPlist.strings */ = { 238 | isa = PBXVariantGroup; 239 | children = ( 240 | 8E4E1ABC17D35355005EB12B /* en */, 241 | ); 242 | name = InfoPlist.strings; 243 | sourceTree = ""; 244 | }; 245 | /* End PBXVariantGroup section */ 246 | 247 | /* Begin XCBuildConfiguration section */ 248 | 8E4E1AD917D35355005EB12B /* Debug */ = { 249 | isa = XCBuildConfiguration; 250 | buildSettings = { 251 | ALWAYS_SEARCH_USER_PATHS = NO; 252 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 253 | CLANG_CXX_LIBRARY = "libc++"; 254 | CLANG_ENABLE_MODULES = YES; 255 | CLANG_ENABLE_OBJC_ARC = YES; 256 | CLANG_WARN_BOOL_CONVERSION = YES; 257 | CLANG_WARN_CONSTANT_CONVERSION = YES; 258 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 259 | CLANG_WARN_EMPTY_BODY = YES; 260 | CLANG_WARN_ENUM_CONVERSION = YES; 261 | CLANG_WARN_INT_CONVERSION = YES; 262 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 265 | COPY_PHASE_STRIP = NO; 266 | GCC_C_LANGUAGE_STANDARD = gnu99; 267 | GCC_DYNAMIC_NO_PIC = NO; 268 | GCC_OPTIMIZATION_LEVEL = 0; 269 | GCC_PREPROCESSOR_DEFINITIONS = ( 270 | "DEBUG=1", 271 | "$(inherited)", 272 | ); 273 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 274 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 275 | GCC_WARN_UNDECLARED_SELECTOR = YES; 276 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 277 | GCC_WARN_UNUSED_FUNCTION = YES; 278 | GCC_WARN_UNUSED_VARIABLE = YES; 279 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 280 | ONLY_ACTIVE_ARCH = YES; 281 | SDKROOT = iphoneos; 282 | }; 283 | name = Debug; 284 | }; 285 | 8E4E1ADA17D35355005EB12B /* Release */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ALWAYS_SEARCH_USER_PATHS = NO; 289 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 290 | CLANG_CXX_LIBRARY = "libc++"; 291 | CLANG_ENABLE_MODULES = YES; 292 | CLANG_ENABLE_OBJC_ARC = YES; 293 | CLANG_WARN_BOOL_CONVERSION = YES; 294 | CLANG_WARN_CONSTANT_CONVERSION = YES; 295 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 296 | CLANG_WARN_EMPTY_BODY = YES; 297 | CLANG_WARN_ENUM_CONVERSION = YES; 298 | CLANG_WARN_INT_CONVERSION = YES; 299 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 300 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 301 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 302 | COPY_PHASE_STRIP = YES; 303 | ENABLE_NS_ASSERTIONS = NO; 304 | GCC_C_LANGUAGE_STANDARD = gnu99; 305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 306 | GCC_WARN_UNDECLARED_SELECTOR = YES; 307 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 308 | GCC_WARN_UNUSED_FUNCTION = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 311 | SDKROOT = iphoneos; 312 | VALIDATE_PRODUCT = YES; 313 | }; 314 | name = Release; 315 | }; 316 | 8E4E1ADC17D35355005EB12B /* Debug */ = { 317 | isa = XCBuildConfiguration; 318 | baseConfigurationReference = 880664D9E4CB6491EE4E5E3C /* Pods-CSNotificationViewDemo.debug.xcconfig */; 319 | buildSettings = { 320 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 321 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 322 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 323 | GCC_PREFIX_HEADER = "CSNotificationViewDemo/CSNotificationViewDemo-Prefix.pch"; 324 | INFOPLIST_FILE = "CSNotificationViewDemo/CSNotificationViewDemo-Info.plist"; 325 | PRODUCT_NAME = CSNotificationViewDemo; 326 | WRAPPER_EXTENSION = app; 327 | }; 328 | name = Debug; 329 | }; 330 | 8E4E1ADD17D35355005EB12B /* Release */ = { 331 | isa = XCBuildConfiguration; 332 | baseConfigurationReference = 9A4F14863F8ED23637102486 /* Pods-CSNotificationViewDemo.release.xcconfig */; 333 | buildSettings = { 334 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 335 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 336 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 337 | GCC_PREFIX_HEADER = "CSNotificationViewDemo/CSNotificationViewDemo-Prefix.pch"; 338 | INFOPLIST_FILE = "CSNotificationViewDemo/CSNotificationViewDemo-Info.plist"; 339 | PRODUCT_NAME = CSNotificationViewDemo; 340 | WRAPPER_EXTENSION = app; 341 | }; 342 | name = Release; 343 | }; 344 | /* End XCBuildConfiguration section */ 345 | 346 | /* Begin XCConfigurationList section */ 347 | 8E4E1AAA17D35355005EB12B /* Build configuration list for PBXProject "CSNotificationViewDemo" */ = { 348 | isa = XCConfigurationList; 349 | buildConfigurations = ( 350 | 8E4E1AD917D35355005EB12B /* Debug */, 351 | 8E4E1ADA17D35355005EB12B /* Release */, 352 | ); 353 | defaultConfigurationIsVisible = 0; 354 | defaultConfigurationName = Release; 355 | }; 356 | 8E4E1ADB17D35355005EB12B /* Build configuration list for PBXNativeTarget "CSNotificationViewDemo" */ = { 357 | isa = XCConfigurationList; 358 | buildConfigurations = ( 359 | 8E4E1ADC17D35355005EB12B /* Debug */, 360 | 8E4E1ADD17D35355005EB12B /* Release */, 361 | ); 362 | defaultConfigurationIsVisible = 0; 363 | defaultConfigurationName = Release; 364 | }; 365 | /* End XCConfigurationList section */ 366 | }; 367 | rootObject = 8E4E1AA717D35355005EB12B /* Project object */; 368 | } 369 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/CSAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSAppDelegate.h 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 01.09.13. 6 | // Copyright (c) 2013 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import 10 | 11 | @interface CSAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/CSAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSAppDelegate.m 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 01.09.13. 6 | // Copyright (c) 2013 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import "CSAppDelegate.h" 10 | 11 | @implementation CSAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | return YES; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/CSDetailsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSDetailsViewController.h 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 24.02.14. 6 | // Copyright (c) 2014 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import 10 | 11 | @interface CSDetailsViewController : UIViewController 12 | 13 | - (IBAction)didPushPresentNotificationView:(id)sender; 14 | 15 | - (IBAction)didPushBack:(id)sender; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/CSDetailsViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSDetailsViewController.m 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 24.02.14. 6 | // Copyright (c) 2014 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import "CSDetailsViewController.h" 10 | #import 11 | 12 | @interface CSDetailsViewController () 13 | 14 | @end 15 | 16 | @implementation CSDetailsViewController 17 | 18 | - (void)viewWillAppear:(BOOL)animated 19 | { 20 | [self.navigationController setNavigationBarHidden:YES animated:YES]; 21 | } 22 | 23 | - (IBAction)didPushBack:(id)sender 24 | { 25 | [self.navigationController popViewControllerAnimated:YES]; 26 | } 27 | 28 | - (IBAction)didPushPresentNotificationView:(id)sender 29 | { 30 | [CSNotificationView showInViewController:self 31 | tintColor:[UIColor colorWithRed:0.000 green:0.6 blue:1.000 alpha:1] 32 | image:nil 33 | message:@"Some message that should resize when showing the navbar again." duration:10.0f]; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/CSNotificationViewDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.cschwarz.${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 | Storyboard 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/CSNotificationViewDemo-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_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/CSRootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSRootViewController.h 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 01.09.13. 6 | // Copyright (c) 2013 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import 10 | 11 | @interface CSRootViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/CSRootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CSRootViewController.m 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 01.09.13. 6 | // Copyright (c) 2013 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import "CSRootViewController.h" 10 | #import "CSNotificationView.h" 11 | 12 | @interface CSRootViewController () 13 | 14 | @property (nonatomic, strong) CSNotificationView* permanentNotification; 15 | 16 | @end 17 | 18 | @implementation CSRootViewController 19 | 20 | - (void)viewWillAppear:(BOOL)animated 21 | { 22 | [self.navigationController setNavigationBarHidden:NO animated:YES]; 23 | } 24 | 25 | - (IBAction)showError:(id)sender { 26 | [CSNotificationView showInViewController:self.navigationController 27 | style:CSNotificationViewStyleError 28 | message:@"A critical error happened."]; 29 | } 30 | - (IBAction)showSuccess:(id)sender { 31 | [CSNotificationView showInViewController:self.navigationController 32 | style:CSNotificationViewStyleSuccess 33 | message:@"Great, it works."]; 34 | } 35 | 36 | - (IBAction)showCustom:(id)sender { 37 | [CSNotificationView showInViewController:self.navigationController 38 | tintColor:[UIColor colorWithRed:0.000 green:0.6 blue:1.000 alpha:1] 39 | image:nil 40 | message:@"No icon and a message that needs two rows and extra " 41 | @"presentation time to be displayed properly." 42 | duration:5.8f]; 43 | 44 | } 45 | 46 | - (IBAction)showModal:(id)sender 47 | { 48 | UIViewController *modalController = [[UIViewController alloc] init]; 49 | modalController.view.backgroundColor = [UIColor whiteColor]; 50 | modalController.navigationItem.title = @"Modal"; 51 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:modalController]; 52 | 53 | __weak UIViewController *weakModalController = modalController; 54 | 55 | [self presentViewController:navController animated:YES completion:^{ 56 | [CSNotificationView showInViewController:weakModalController 57 | style:CSNotificationViewStyleSuccess 58 | message:@"To be dismissed after the view controller dismisses"]; 59 | }]; 60 | 61 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((1.0) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 62 | [weakModalController dismissViewControllerAnimated:YES completion:nil]; 63 | }); 64 | 65 | } 66 | 67 | - (IBAction)showPermanent:(id)sender 68 | { 69 | if (self.permanentNotification) { 70 | return; 71 | } 72 | 73 | self.permanentNotification = 74 | [CSNotificationView notificationViewWithParentViewController:self.navigationController 75 | tintColor:[UIColor colorWithRed:0.000 green:0.6 blue:1.000 alpha:1] 76 | image:nil message:@"I am running for two seconds."]; 77 | 78 | [self.permanentNotification setShowingActivity:YES]; 79 | 80 | __block typeof(self) weakself = self; 81 | self.permanentNotification.tapHandler = ^{ 82 | [weakself cancel]; 83 | }; 84 | 85 | [self.permanentNotification setVisible:YES animated:YES completion:^{ 86 | 87 | weakself.navigationItem.rightBarButtonItem = 88 | [[UIBarButtonItem alloc] initWithTitle:@"Cancel" 89 | style:UIBarButtonItemStyleDone 90 | target:weakself 91 | action:@selector(cancel)]; 92 | 93 | double delayInSeconds = 2.0; 94 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 95 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 96 | [weakself success]; 97 | }); 98 | 99 | }]; 100 | } 101 | 102 | - (void)cancel 103 | { 104 | self.navigationItem.rightBarButtonItem = nil; 105 | [self.permanentNotification dismissWithStyle:CSNotificationViewStyleError 106 | message:@"Cancelled" 107 | duration:kCSNotificationViewDefaultShowDuration animated:YES]; 108 | self.permanentNotification = nil; 109 | 110 | } 111 | 112 | - (void)success 113 | { 114 | self.navigationItem.rightBarButtonItem = nil; 115 | [self.permanentNotification dismissWithStyle:CSNotificationViewStyleSuccess 116 | message:@"Sucess!" 117 | duration:kCSNotificationViewDefaultShowDuration animated:YES]; 118 | self.permanentNotification = nil; 119 | } 120 | 121 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 122 | [self performSegueWithIdentifier:@"push" sender:nil]; 123 | } 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/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 | } -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/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 | } -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/Storyboard.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 376 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/CSNotificationViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CSNotificationViewDemo 4 | // 5 | // Created by Christian Schwarz on 01.09.13. 6 | // Copyright (c) 2013 Christian Schwarz. Check LICENSE.md. 7 | // 8 | 9 | #import 10 | 11 | #import "CSAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([CSAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, "7.0" 2 | 3 | # In case you want to demo/test CocoaPods frameworks 4 | # use_frameworks! 5 | 6 | target "CSNotificationViewDemo" do 7 | pod "CSNotificationView", :path => "../" 8 | end 9 | 10 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CSNotificationView (0.5.4) 3 | 4 | DEPENDENCIES: 5 | - CSNotificationView (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | CSNotificationView: 9 | :path: ../ 10 | 11 | SPEC CHECKSUMS: 12 | CSNotificationView: 0792f5220163c2befaf1a9716aa3d5a7d6bd4fb1 13 | 14 | COCOAPODS: 0.36.3 15 | -------------------------------------------------------------------------------- /Icons/checkmark.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/problame/CSNotificationView/37c9091f255d1f8da1a4354c8260037d708a9fab/Icons/checkmark.pxm -------------------------------------------------------------------------------- /Icons/exclamation_mark.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/problame/CSNotificationView/37c9091f255d1f8da1a4354c8260037d708a9fab/Icons/exclamation_mark.pxm -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Christian Schwarz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #CSNotificationView 2 | 3 | Easy to use, semi-translucent and blurring notification view that drops into `UIView`, `UITableView`, `UICollectionView`. 4 | Also supports displaying progress. 5 | 6 | **Supports iOS 7 and iOS 8. Requires Xcode 6.** 7 | 8 | 9 |
10 | 11 |   12 | 13 |   14 | 15 | 16 | 17 |
18 | 19 | ##Example code 20 | 21 | ###Quick presentation 22 | 23 | ```objc 24 | [CSNotificationView showInViewController:self 25 | style:CSNotificationViewStyleError 26 | message:@"A critical error happened."]; 27 | 28 | [CSNotificationView showInViewController:self 29 | style:CSNotificationViewStyleSuccess 30 | message:@"Great, it works."]; 31 | 32 | 33 | ``` 34 | 35 | ###UIActivityIndicatorView built-in 36 | 37 | ```objc 38 | CSNotificationView* note = (...); 39 | note.showingActivity = YES; 40 | 41 | [note setVisible:YES animated:YES completion:nil]; 42 | (...) 43 | [note dismissWithStyle:CSNotificationViewStyleSuccess message:@"Success!" 44 | duration:kCSNotificationViewDefaultShowDuration animated:YES]; 45 | ``` 46 | 47 | ###Tap handling 48 | 49 | Handle tap events on the notification using a block callback 50 | 51 | ```objc 52 | __block typeof(self) weakSelf = self; 53 | self.loadingNotificationView.tapHandler = ^{ 54 | [weakSelf cancelOperationXYZ]; 55 | [weakSelf.loadingNotificationView dismissWithStyle:CSNotificationViewStyleError 56 | message:@"Cancelled" 57 | duration:kCSNotificationViewDefaultShowDuration animated:YES]; 58 | }; 59 | ``` 60 | 61 | ###Customization 62 | 63 | ####Custom image / icon 64 | 65 | ```objc 66 | note.image = [UIImage imageNamed:@"mustache"]; 67 | ``` 68 | 69 | ####Flexible with text & no images 70 | 71 | ```objc 72 | [CSNotificationView showInViewController:self 73 | tintColor:[UIColor colorWithRed:0.000 green:0.6 blue:1.000 alpha:1] 74 | image:nil 75 | message:@"No icon and a message that needs two rows and extra \ 76 | presentation time to be displayed properly." 77 | duration:5.8f]; 78 | 79 | ``` 80 | 81 | 82 | ##License 83 | 84 | See [LICENSE.md](https://raw.github.com/problame/CSNotificationView/master/LICENSE.md) 85 | --------------------------------------------------------------------------------