├── .gitignore ├── Demo ├── Classes │ ├── DemoAppDelegate.h │ ├── DemoAppDelegate.m │ ├── DemoViewController.h │ └── DemoViewController.m ├── Default-568h@2x.png ├── DemoViewController.xib ├── GCDiscreetNotificationViewDemo-Info.plist ├── GCDiscreetNotificationViewDemo.xcodeproj │ └── project.pbxproj ├── GCDiscreetNotificationViewDemo_Prefix.pch ├── MainWindow.xib └── main.m ├── GCDiscreetNotificationView ├── GCDiscreetNotificationView.h └── GCDiscreetNotificationView.m ├── LICENSE.txt └── README.textile /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X 2 | *.DS_Store 3 | 4 | # Xcode 5 | *.pbxuser 6 | *.mode1v3 7 | *.mode2v3 8 | *.perspectivev3 9 | *.xcuserstate 10 | project.xcworkspace/ 11 | xcuserdata/ 12 | 13 | # Generated files 14 | build/ 15 | *.[oa] 16 | *.pyc 17 | 18 | # Backup files 19 | *~.nib -------------------------------------------------------------------------------- /Demo/Classes/DemoAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoAppDelegate.h 3 | // Demo 4 | // 5 | // Created by Guillaume Campagna on 09-12-28. 6 | // Copyright LittleKiwi 2009. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class DemoViewController; 12 | 13 | @interface DemoAppDelegate : NSObject 14 | 15 | @property (nonatomic, retain) IBOutlet UIWindow *window; 16 | @property (nonatomic, retain) IBOutlet DemoViewController *viewController; 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /Demo/Classes/DemoAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoAppDelegate.m 3 | // Demo 4 | // 5 | // Created by Guillaume Campagna on 09-12-28. 6 | // Copyright LittleKiwi 2009. All rights reserved. 7 | // 8 | 9 | #import "DemoAppDelegate.h" 10 | #import "DemoViewController.h" 11 | 12 | @implementation DemoAppDelegate 13 | 14 | @synthesize window; 15 | @synthesize viewController; 16 | 17 | - (void)applicationDidFinishLaunching:(UIApplication *)application { 18 | window.rootViewController = viewController; 19 | [window makeKeyAndVisible]; 20 | } 21 | 22 | - (void)dealloc { 23 | [viewController release]; 24 | [window release]; 25 | [super dealloc]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Demo/Classes/DemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoViewController.h 3 | // Demo 4 | // 5 | // Created by Guillaume Campagna on 09-12-28. 6 | // Copyright LittleKiwi 2009. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class GCDiscreetNotificationView; 12 | 13 | @interface DemoViewController : UIViewController 14 | 15 | @property (nonatomic, retain) IBOutlet UISwitch *activitySwitch; 16 | @property (nonatomic, retain) IBOutlet UISwitch *topBottomSwitch; 17 | @property (nonatomic, retain) IBOutlet UITextField *textField; 18 | @property (nonatomic, retain) GCDiscreetNotificationView *notificationView; 19 | 20 | - (IBAction) changeActivity:(id) sender; 21 | - (IBAction) changeTopBottom:(id) sender; 22 | - (IBAction) show; 23 | - (IBAction) hide; 24 | - (IBAction) hideAfter1sec; 25 | 26 | @end 27 | 28 | -------------------------------------------------------------------------------- /Demo/Classes/DemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoViewController.m 3 | // Demo 4 | // 5 | // Created by Guillaume Campagna on 09-12-28. 6 | // Copyright LittleKiwi 2009. All rights reserved. 7 | // 8 | 9 | #import "DemoViewController.h" 10 | #import "GCDiscreetNotificationView.h" 11 | 12 | @implementation DemoViewController 13 | 14 | @synthesize activitySwitch; 15 | @synthesize topBottomSwitch; 16 | @synthesize textField; 17 | @synthesize notificationView; 18 | 19 | // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | 23 | notificationView = [[GCDiscreetNotificationView alloc] initWithText:self.textField.text 24 | showActivity:self.activitySwitch.on 25 | inPresentationMode:self.topBottomSwitch.on ? GCDiscreetNotificationViewPresentationModeTop : GCDiscreetNotificationViewPresentationModeBottom 26 | inView:self.view]; 27 | } 28 | 29 | - (void) show { 30 | [self.notificationView show:YES]; 31 | } 32 | 33 | - (void) hide { 34 | [self.notificationView hide:YES]; 35 | } 36 | 37 | - (IBAction) hideAfter1sec { 38 | [self.notificationView hideAnimatedAfter:1.0]; 39 | } 40 | 41 | - (void) changeActivity:(id)sender { 42 | [self.notificationView setShowActivity:self.activitySwitch.on animated:YES]; 43 | } 44 | 45 | - (void) changeTopBottom:(id)sender { 46 | [self.notificationView setPresentationMode:self.topBottomSwitch.on ? GCDiscreetNotificationViewPresentationModeTop : GCDiscreetNotificationViewPresentationModeBottom]; 47 | } 48 | 49 | - (BOOL) textFieldShouldReturn:(UITextField *)aTextField { 50 | [self.textField resignFirstResponder]; 51 | [self.notificationView setTextLabel:self.textField.text animated:YES]; 52 | return NO; 53 | } 54 | 55 | - (NSUInteger)supportedInterfaceOrientations { 56 | return UIInterfaceOrientationMaskAll; 57 | } 58 | 59 | - (BOOL)shouldAutorotate { 60 | return YES; 61 | } 62 | 63 | - (void)dealloc { 64 | [activitySwitch release]; 65 | activitySwitch = nil; 66 | [topBottomSwitch release]; 67 | topBottomSwitch = nil; 68 | [textField release]; 69 | textField = nil; 70 | [notificationView release]; 71 | notificationView = nil; 72 | 73 | [super dealloc]; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /Demo/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gcamp/GCDiscreetNotificationView/d7b030989aa927c146cae66d1c9b8efbdf33278a/Demo/Default-568h@2x.png -------------------------------------------------------------------------------- /Demo/DemoViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1552 5 | 12C60 6 | 3084 7 | 1187.34 8 | 625.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 2083 12 | 13 | 14 | YES 15 | IBProxyObject 16 | IBUIButton 17 | IBUILabel 18 | IBUISwitch 19 | IBUITextField 20 | IBUIView 21 | 22 | 23 | YES 24 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 25 | 26 | 27 | PluginDependencyRecalculationVersion 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | 42 | 274 43 | 44 | YES 45 | 46 | 47 | 293 48 | {{20, 49}, {280, 37}} 49 | 50 | 51 | 52 | NO 53 | NO 54 | IBCocoaTouchFramework 55 | 0 56 | 0 57 | 1 58 | Show 59 | 60 | 3 61 | MQA 62 | 63 | 64 | 1 65 | MC4xOTYwNzg0MyAwLjMwOTgwMzkzIDAuNTIxNTY4NjYAA 66 | 67 | 68 | 3 69 | MC41AA 70 | 71 | 72 | Helvetica-Bold 73 | Helvetica 74 | 2 75 | 15 76 | 77 | 78 | Helvetica-Bold 79 | 15 80 | 16 81 | 82 | 83 | 84 | 85 | 292 86 | {{113, 349}, {94, 27}} 87 | 88 | 89 | 90 | NO 91 | YES 92 | YES 93 | IBCocoaTouchFramework 94 | 0 95 | 0 96 | YES 97 | 98 | 99 | 100 | 292 101 | {{215, 352}, {42, 21}} 102 | 103 | 104 | 105 | NO 106 | YES 107 | NO 108 | IBCocoaTouchFramework 109 | Top 110 | 111 | 1 112 | MCAwIDAAA 113 | darkTextColor 114 | 115 | 116 | 1 117 | 10 118 | 119 | 1 120 | 17 121 | 122 | 123 | Helvetica 124 | 17 125 | 16 126 | 127 | 128 | 129 | 130 | 292 131 | {{45, 352}, {54, 21}} 132 | 133 | 134 | 135 | NO 136 | YES 137 | NO 138 | IBCocoaTouchFramework 139 | Bottom 140 | 141 | 142 | 1 143 | 10 144 | 145 | 146 | 147 | 148 | 149 | 292 150 | {{113, 384}, {94, 27}} 151 | 152 | 153 | 154 | NO 155 | YES 156 | YES 157 | IBCocoaTouchFramework 158 | 0 159 | 0 160 | YES 161 | 162 | 163 | 164 | 292 165 | {{215, 387}, {54, 21}} 166 | 167 | 168 | 169 | NO 170 | YES 171 | NO 172 | IBCocoaTouchFramework 173 | Activity 174 | 175 | 176 | 1 177 | 10 178 | 179 | 180 | 181 | 182 | 183 | 292 184 | {{20, 387}, {79, 21}} 185 | 186 | 187 | 188 | NO 189 | YES 190 | NO 191 | IBCocoaTouchFramework 192 | No activity 193 | 194 | 195 | 1 196 | 10 197 | 198 | 199 | 200 | 201 | 202 | 292 203 | {{20, 184}, {280, 31}} 204 | 205 | 206 | 207 | NO 208 | NO 209 | IBCocoaTouchFramework 210 | 0 211 | TextValue 212 | 3 213 | 214 | 3 215 | MAA 216 | 217 | 2 218 | 219 | 220 | YES 221 | YES 222 | 17 223 | 224 | 1 225 | 9 226 | YES 227 | IBCocoaTouchFramework 228 | 229 | 230 | 1 231 | 12 232 | 233 | 234 | Helvetica 235 | 12 236 | 16 237 | 238 | 239 | 240 | 241 | 293 242 | {{20, 94}, {280, 37}} 243 | 244 | 245 | 246 | NO 247 | NO 248 | IBCocoaTouchFramework 249 | 0 250 | 0 251 | 1 252 | Hide 253 | 254 | 255 | 1 256 | MC4xOTYwNzg0MyAwLjMwOTgwMzkzIDAuNTIxNTY4NjYAA 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 293 265 | {{20, 139}, {280, 37}} 266 | 267 | 268 | 269 | NO 270 | NO 271 | IBCocoaTouchFramework 272 | 0 273 | 0 274 | 1 275 | Hide After 1 sec 276 | 277 | 278 | 1 279 | MC4xOTYwNzg0MyAwLjMwOTgwMzkzIDAuNTIxNTY4NjYAA 280 | 281 | 282 | 283 | 284 | 285 | 286 | {{0, 20}, {320, 460}} 287 | 288 | 289 | 290 | 291 | 3 292 | MC43NQA 293 | 294 | 295 | NO 296 | 297 | IBCocoaTouchFramework 298 | 299 | 300 | 301 | 302 | YES 303 | 304 | 305 | view 306 | 307 | 308 | 309 | 7 310 | 311 | 312 | 313 | textField 314 | 315 | 316 | 317 | 16 318 | 319 | 320 | 321 | topBottomSwitch 322 | 323 | 324 | 325 | 18 326 | 327 | 328 | 329 | activitySwitch 330 | 331 | 332 | 333 | 19 334 | 335 | 336 | 337 | show 338 | 339 | 340 | 7 341 | 342 | 23 343 | 344 | 345 | 346 | changeTopBottom: 347 | 348 | 349 | 13 350 | 351 | 22 352 | 353 | 354 | 355 | changeActivity: 356 | 357 | 358 | 13 359 | 360 | 20 361 | 362 | 363 | 364 | delegate 365 | 366 | 367 | 368 | 27 369 | 370 | 371 | 372 | hide 373 | 374 | 375 | 7 376 | 377 | 26 378 | 379 | 380 | 381 | hideAfter1sec 382 | 383 | 384 | 7 385 | 386 | 31 387 | 388 | 389 | 390 | 391 | YES 392 | 393 | 0 394 | 395 | YES 396 | 397 | 398 | 399 | 400 | 401 | -1 402 | 403 | 404 | File's Owner 405 | 406 | 407 | -2 408 | 409 | 410 | 411 | 412 | 6 413 | 414 | 415 | YES 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 8 431 | 432 | 433 | 434 | 435 | 9 436 | 437 | 438 | 439 | 440 | 10 441 | 442 | 443 | 444 | 445 | 11 446 | 447 | 448 | 449 | 450 | 12 451 | 452 | 453 | 454 | 455 | 13 456 | 457 | 458 | 459 | 460 | 14 461 | 462 | 463 | 464 | 465 | 15 466 | 467 | 468 | 469 | 470 | 24 471 | 472 | 473 | 474 | 475 | 29 476 | 477 | 478 | 479 | 480 | 481 | 482 | YES 483 | 484 | YES 485 | -1.CustomClassName 486 | -1.IBPluginDependency 487 | -2.CustomClassName 488 | -2.IBPluginDependency 489 | 10.IBPluginDependency 490 | 11.IBPluginDependency 491 | 12.IBPluginDependency 492 | 13.IBPluginDependency 493 | 14.IBPluginDependency 494 | 15.IBPluginDependency 495 | 24.IBPluginDependency 496 | 29.IBPluginDependency 497 | 6.IBPluginDependency 498 | 8.IBPluginDependency 499 | 9.IBPluginDependency 500 | 501 | 502 | YES 503 | DemoViewController 504 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 505 | UIResponder 506 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 507 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 508 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 509 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 510 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 511 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 512 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 513 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 514 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 515 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 516 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 517 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 518 | 519 | 520 | 521 | YES 522 | 523 | 524 | 525 | 526 | 527 | YES 528 | 529 | 530 | 531 | 532 | 31 533 | 534 | 535 | 536 | YES 537 | 538 | DemoViewController 539 | UIViewController 540 | 541 | YES 542 | 543 | YES 544 | changeActivity: 545 | changeTopBottom: 546 | hide 547 | hideAfter1sec 548 | show 549 | 550 | 551 | YES 552 | id 553 | id 554 | id 555 | id 556 | id 557 | 558 | 559 | 560 | YES 561 | 562 | YES 563 | changeActivity: 564 | changeTopBottom: 565 | hide 566 | hideAfter1sec 567 | show 568 | 569 | 570 | YES 571 | 572 | changeActivity: 573 | id 574 | 575 | 576 | changeTopBottom: 577 | id 578 | 579 | 580 | hide 581 | id 582 | 583 | 584 | hideAfter1sec 585 | id 586 | 587 | 588 | show 589 | id 590 | 591 | 592 | 593 | 594 | YES 595 | 596 | YES 597 | activitySwitch 598 | textField 599 | topBottomSwitch 600 | 601 | 602 | YES 603 | UISwitch 604 | UITextField 605 | UISwitch 606 | 607 | 608 | 609 | YES 610 | 611 | YES 612 | activitySwitch 613 | textField 614 | topBottomSwitch 615 | 616 | 617 | YES 618 | 619 | activitySwitch 620 | UISwitch 621 | 622 | 623 | textField 624 | UITextField 625 | 626 | 627 | topBottomSwitch 628 | UISwitch 629 | 630 | 631 | 632 | 633 | IBProjectSource 634 | ./Classes/DemoViewController.h 635 | 636 | 637 | 638 | 639 | 0 640 | IBCocoaTouchFramework 641 | 642 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 643 | 644 | 645 | YES 646 | 3 647 | 2083 648 | 649 | 650 | -------------------------------------------------------------------------------- /Demo/GCDiscreetNotificationViewDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.yourcompany.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile 28 | MainWindow 29 | 30 | 31 | -------------------------------------------------------------------------------- /Demo/GCDiscreetNotificationViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D3623260D0F684500981E51 /* DemoAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* DemoAppDelegate.m */; }; 11 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 12 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 13 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 14 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; 15 | 2899E5220DE3E06400AC0155 /* DemoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2899E5210DE3E06400AC0155 /* DemoViewController.xib */; }; 16 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; 17 | 28D7ACF80DDB3853001CB0EB /* DemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* DemoViewController.m */; }; 18 | B081573D16C03D3F005AAA49 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B081573C16C03D3F005AAA49 /* Default-568h@2x.png */; }; 19 | B0E88F8E135FC7FB00EC3BA7 /* GCDiscreetNotificationView.m in Sources */ = {isa = PBXBuildFile; fileRef = B0E88F8D135FC7FB00EC3BA7 /* GCDiscreetNotificationView.m */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 24 | 1D3623240D0F684500981E51 /* DemoAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoAppDelegate.h; sourceTree = ""; }; 25 | 1D3623250D0F684500981E51 /* DemoAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoAppDelegate.m; sourceTree = ""; }; 26 | 1D6058910D05DD3D006BFB54 /* GCDiscreetNotificationViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GCDiscreetNotificationViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 28 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 29 | 2899E5210DE3E06400AC0155 /* DemoViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DemoViewController.xib; sourceTree = ""; }; 30 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 31 | 28D7ACF60DDB3853001CB0EB /* DemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoViewController.h; sourceTree = ""; }; 32 | 28D7ACF70DDB3853001CB0EB /* DemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoViewController.m; sourceTree = ""; }; 33 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 34 | 32CA4F630368D1EE00C91783 /* GCDiscreetNotificationViewDemo_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDiscreetNotificationViewDemo_Prefix.pch; sourceTree = ""; }; 35 | 8D1107310486CEB800E47090 /* GCDiscreetNotificationViewDemo-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GCDiscreetNotificationViewDemo-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; 36 | B081573C16C03D3F005AAA49 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 37 | B0E88F8C135FC7FB00EC3BA7 /* GCDiscreetNotificationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDiscreetNotificationView.h; sourceTree = ""; }; 38 | B0E88F8D135FC7FB00EC3BA7 /* GCDiscreetNotificationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDiscreetNotificationView.m; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 47 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 48 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | /* End PBXFrameworksBuildPhase section */ 53 | 54 | /* Begin PBXGroup section */ 55 | 080E96DDFE201D6D7F000001 /* Classes */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | 1D3623240D0F684500981E51 /* DemoAppDelegate.h */, 59 | 1D3623250D0F684500981E51 /* DemoAppDelegate.m */, 60 | 28D7ACF60DDB3853001CB0EB /* DemoViewController.h */, 61 | 28D7ACF70DDB3853001CB0EB /* DemoViewController.m */, 62 | ); 63 | path = Classes; 64 | sourceTree = ""; 65 | }; 66 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 1D6058910D05DD3D006BFB54 /* GCDiscreetNotificationViewDemo.app */, 70 | ); 71 | name = Products; 72 | sourceTree = ""; 73 | }; 74 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | B081573C16C03D3F005AAA49 /* Default-568h@2x.png */, 78 | B0E88F8B135FC7FB00EC3BA7 /* GCDiscreetNotificationView */, 79 | 080E96DDFE201D6D7F000001 /* Classes */, 80 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 81 | 29B97317FDCFA39411CA2CEA /* Resources */, 82 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 83 | 19C28FACFE9D520D11CA2CBB /* Products */, 84 | ); 85 | name = CustomTemplate; 86 | sourceTree = ""; 87 | }; 88 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 32CA4F630368D1EE00C91783 /* GCDiscreetNotificationViewDemo_Prefix.pch */, 92 | 29B97316FDCFA39411CA2CEA /* main.m */, 93 | ); 94 | name = "Other Sources"; 95 | sourceTree = ""; 96 | }; 97 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 2899E5210DE3E06400AC0155 /* DemoViewController.xib */, 101 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */, 102 | 8D1107310486CEB800E47090 /* GCDiscreetNotificationViewDemo-Info.plist */, 103 | ); 104 | name = Resources; 105 | sourceTree = ""; 106 | }; 107 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 111 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 112 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */, 113 | ); 114 | name = Frameworks; 115 | sourceTree = ""; 116 | }; 117 | B0E88F8B135FC7FB00EC3BA7 /* GCDiscreetNotificationView */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | B0E88F8C135FC7FB00EC3BA7 /* GCDiscreetNotificationView.h */, 121 | B0E88F8D135FC7FB00EC3BA7 /* GCDiscreetNotificationView.m */, 122 | ); 123 | name = GCDiscreetNotificationView; 124 | path = ../GCDiscreetNotificationView; 125 | sourceTree = ""; 126 | }; 127 | /* End PBXGroup section */ 128 | 129 | /* Begin PBXNativeTarget section */ 130 | 1D6058900D05DD3D006BFB54 /* GCDiscreetNotificationViewDemo */ = { 131 | isa = PBXNativeTarget; 132 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "GCDiscreetNotificationViewDemo" */; 133 | buildPhases = ( 134 | 1D60588D0D05DD3D006BFB54 /* Resources */, 135 | 1D60588E0D05DD3D006BFB54 /* Sources */, 136 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 137 | ); 138 | buildRules = ( 139 | ); 140 | dependencies = ( 141 | ); 142 | name = GCDiscreetNotificationViewDemo; 143 | productName = Demo; 144 | productReference = 1D6058910D05DD3D006BFB54 /* GCDiscreetNotificationViewDemo.app */; 145 | productType = "com.apple.product-type.application"; 146 | }; 147 | /* End PBXNativeTarget section */ 148 | 149 | /* Begin PBXProject section */ 150 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 151 | isa = PBXProject; 152 | attributes = { 153 | LastUpgradeCheck = 0460; 154 | }; 155 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "GCDiscreetNotificationViewDemo" */; 156 | compatibilityVersion = "Xcode 3.2"; 157 | developmentRegion = English; 158 | hasScannedForEncodings = 1; 159 | knownRegions = ( 160 | en, 161 | ); 162 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 163 | projectDirPath = ""; 164 | projectRoot = ""; 165 | targets = ( 166 | 1D6058900D05DD3D006BFB54 /* GCDiscreetNotificationViewDemo */, 167 | ); 168 | }; 169 | /* End PBXProject section */ 170 | 171 | /* Begin PBXResourcesBuildPhase section */ 172 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 173 | isa = PBXResourcesBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, 177 | 2899E5220DE3E06400AC0155 /* DemoViewController.xib in Resources */, 178 | B081573D16C03D3F005AAA49 /* Default-568h@2x.png in Resources */, 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | /* End PBXResourcesBuildPhase section */ 183 | 184 | /* Begin PBXSourcesBuildPhase section */ 185 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 186 | isa = PBXSourcesBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 190 | 1D3623260D0F684500981E51 /* DemoAppDelegate.m in Sources */, 191 | 28D7ACF80DDB3853001CB0EB /* DemoViewController.m in Sources */, 192 | B0E88F8E135FC7FB00EC3BA7 /* GCDiscreetNotificationView.m in Sources */, 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | }; 196 | /* End PBXSourcesBuildPhase section */ 197 | 198 | /* Begin XCBuildConfiguration section */ 199 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 200 | isa = XCBuildConfiguration; 201 | buildSettings = { 202 | ALWAYS_SEARCH_USER_PATHS = NO; 203 | BUILD_STYLE = Debug; 204 | COPY_PHASE_STRIP = NO; 205 | GCC_DYNAMIC_NO_PIC = NO; 206 | GCC_OPTIMIZATION_LEVEL = 0; 207 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 208 | GCC_PREFIX_HEADER = GCDiscreetNotificationViewDemo_Prefix.pch; 209 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 210 | INFOPLIST_FILE = "GCDiscreetNotificationViewDemo-Info.plist"; 211 | IPHONEOS_DEPLOYMENT_TARGET = 3.0; 212 | PRODUCT_NAME = GCDiscreetNotificationViewDemo; 213 | }; 214 | name = Debug; 215 | }; 216 | 1D6058950D05DD3E006BFB54 /* Release */ = { 217 | isa = XCBuildConfiguration; 218 | buildSettings = { 219 | ALWAYS_SEARCH_USER_PATHS = NO; 220 | BUILD_STYLE = Release; 221 | COPY_PHASE_STRIP = YES; 222 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 223 | GCC_PREFIX_HEADER = GCDiscreetNotificationViewDemo_Prefix.pch; 224 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 225 | INFOPLIST_FILE = "GCDiscreetNotificationViewDemo-Info.plist"; 226 | IPHONEOS_DEPLOYMENT_TARGET = 3.0; 227 | PRODUCT_NAME = GCDiscreetNotificationViewDemo; 228 | }; 229 | name = Release; 230 | }; 231 | C01FCF4F08A954540054247B /* Debug */ = { 232 | isa = XCBuildConfiguration; 233 | buildSettings = { 234 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 235 | BUILD_STYLE = Debug; 236 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 237 | GCC_C_LANGUAGE_STANDARD = c99; 238 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 239 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 240 | GCC_WARN_UNUSED_VARIABLE = YES; 241 | SDKROOT = iphoneos; 242 | }; 243 | name = Debug; 244 | }; 245 | C01FCF5008A954540054247B /* Release */ = { 246 | isa = XCBuildConfiguration; 247 | buildSettings = { 248 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 249 | BUILD_STYLE = Release; 250 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 251 | GCC_C_LANGUAGE_STANDARD = c99; 252 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 253 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 254 | GCC_WARN_UNUSED_VARIABLE = YES; 255 | SDKROOT = iphoneos; 256 | }; 257 | name = Release; 258 | }; 259 | /* End XCBuildConfiguration section */ 260 | 261 | /* Begin XCConfigurationList section */ 262 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "GCDiscreetNotificationViewDemo" */ = { 263 | isa = XCConfigurationList; 264 | buildConfigurations = ( 265 | 1D6058940D05DD3E006BFB54 /* Debug */, 266 | 1D6058950D05DD3E006BFB54 /* Release */, 267 | ); 268 | defaultConfigurationIsVisible = 0; 269 | defaultConfigurationName = Release; 270 | }; 271 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "GCDiscreetNotificationViewDemo" */ = { 272 | isa = XCConfigurationList; 273 | buildConfigurations = ( 274 | C01FCF4F08A954540054247B /* Debug */, 275 | C01FCF5008A954540054247B /* Release */, 276 | ); 277 | defaultConfigurationIsVisible = 0; 278 | defaultConfigurationName = Release; 279 | }; 280 | /* End XCConfigurationList section */ 281 | }; 282 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 283 | } 284 | -------------------------------------------------------------------------------- /Demo/GCDiscreetNotificationViewDemo_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Demo' target in the 'Demo' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /Demo/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 784 5 | 10A394 6 | 732 7 | 1027.1 8 | 430.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 60 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | 35 | 36 | IBFirstResponder 37 | 38 | 39 | 40 | DemoViewController 41 | 42 | 43 | 44 | 45 | 292 46 | {320, 480} 47 | 48 | 1 49 | MSAxIDEAA 50 | 51 | NO 52 | NO 53 | 54 | 55 | 56 | 57 | 58 | YES 59 | 60 | 61 | delegate 62 | 63 | 64 | 65 | 4 66 | 67 | 68 | 69 | viewController 70 | 71 | 72 | 73 | 11 74 | 75 | 76 | 77 | window 78 | 79 | 80 | 81 | 14 82 | 83 | 84 | 85 | 86 | YES 87 | 88 | 0 89 | 90 | 91 | 92 | 93 | 94 | -1 95 | 96 | 97 | File's Owner 98 | 99 | 100 | 3 101 | 102 | 103 | Demo App Delegate 104 | 105 | 106 | -2 107 | 108 | 109 | 110 | 111 | 10 112 | 113 | 114 | 115 | 116 | 12 117 | 118 | 119 | 120 | 121 | 122 | 123 | YES 124 | 125 | YES 126 | -1.CustomClassName 127 | -2.CustomClassName 128 | 10.CustomClassName 129 | 10.IBEditorWindowLastContentRect 130 | 10.IBPluginDependency 131 | 12.IBEditorWindowLastContentRect 132 | 12.IBPluginDependency 133 | 3.CustomClassName 134 | 3.IBPluginDependency 135 | 136 | 137 | YES 138 | UIApplication 139 | UIResponder 140 | DemoViewController 141 | {{512, 351}, {320, 480}} 142 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 143 | {{525, 346}, {320, 480}} 144 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 145 | DemoAppDelegate 146 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 147 | 148 | 149 | 150 | YES 151 | 152 | 153 | YES 154 | 155 | 156 | 157 | 158 | YES 159 | 160 | 161 | YES 162 | 163 | 164 | 165 | 14 166 | 167 | 168 | 169 | YES 170 | 171 | DemoAppDelegate 172 | NSObject 173 | 174 | YES 175 | 176 | YES 177 | viewController 178 | window 179 | 180 | 181 | YES 182 | DemoViewController 183 | UIWindow 184 | 185 | 186 | 187 | IBProjectSource 188 | Classes/DemoAppDelegate.h 189 | 190 | 191 | 192 | DemoAppDelegate 193 | NSObject 194 | 195 | IBUserSource 196 | 197 | 198 | 199 | 200 | DemoViewController 201 | UIViewController 202 | 203 | IBProjectSource 204 | Classes/DemoViewController.h 205 | 206 | 207 | 208 | 209 | 0 210 | 211 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 212 | 213 | 214 | YES 215 | Demo.xcodeproj 216 | 3 217 | 3.1 218 | 219 | 220 | -------------------------------------------------------------------------------- /Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Demo 4 | // 5 | // Created by Guillaume Campagna on 09-12-28. 6 | // Copyright LittleKiwi 2009. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) { 12 | 13 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | [pool release]; 16 | return retVal; 17 | } 18 | -------------------------------------------------------------------------------- /GCDiscreetNotificationView/GCDiscreetNotificationView.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCDiscreetNotificationView.h 3 | // Mtl mobile 4 | // 5 | // Created by Guillaume Campagna on 09-12-27. 6 | // Copyright 2009 LittleKiwi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //The presentation mode of the notification, it sticks to the top or buttom of the content view 12 | typedef enum { 13 | GCDiscreetNotificationViewPresentationModeTop, 14 | GCDiscreetNotificationViewPresentationModeBottom, 15 | } GCDiscreetNotificationViewPresentationMode; 16 | 17 | @interface GCDiscreetNotificationView : UIView 18 | 19 | //You can access the label and the activity indicator to change its values. 20 | //If you want to change the text or the activity itself, use textLabel and showActivity proprieties. 21 | @property (strong, nonatomic, readonly) UILabel *label; 22 | @property (strong, nonatomic, readonly) UIActivityIndicatorView *activityIndicator; 23 | 24 | @property (weak, nonatomic) UIView *view; //The content view where the notification will be shown 25 | @property (nonatomic) GCDiscreetNotificationViewPresentationMode presentationMode; 26 | @property (nonatomic, copy) NSString* textLabel; 27 | @property (nonatomic) BOOL showActivity; 28 | 29 | @property (nonatomic, readonly, getter = isShowing) BOOL showing; 30 | 31 | - (id) initWithText:(NSString *)text inView:(UIView *)aView; 32 | - (id) initWithText:(NSString *)text showActivity:(BOOL)activity inView:(UIView *)aView; 33 | - (id) initWithText:(NSString *)text showActivity:(BOOL)activity inPresentationMode:(GCDiscreetNotificationViewPresentationMode) aPresentationMode inView:(UIView *)aView; 34 | 35 | //Show/Hide animated 36 | - (void) showAnimated; 37 | - (void) hideAnimated; 38 | - (void) hideAnimatedAfter:(NSTimeInterval) timeInterval; 39 | - (void) show:(BOOL) animated; 40 | - (void) hide:(BOOL) animated; 41 | - (void) showAndDismissAutomaticallyAnimated; 42 | - (void) showAndDismissAfter:(NSTimeInterval) timeInterval; 43 | 44 | //Change proprieties in a animated fashion 45 | //If you need to change propreties, you NEED to use these methods. Hiding, changing value, and show it back will NOT work. 46 | - (void) setTextLabel:(NSString *) aText animated:(BOOL) animated; 47 | - (void) setShowActivity:(BOOL) activity animated:(BOOL) animated; 48 | - (void) setTextLabel:(NSString *)aText andSetShowActivity:(BOOL)activity animated:(BOOL)animated; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /GCDiscreetNotificationView/GCDiscreetNotificationView.m: -------------------------------------------------------------------------------- 1 | // 2 | // GCDiscreetNotificationView.m 3 | // Mtl mobile 4 | // 5 | // Created by Guillaume Campagna on 09-12-27. 6 | // Copyright 2009 LittleKiwi. All rights reserved. 7 | // 8 | 9 | #import "GCDiscreetNotificationView.h" 10 | 11 | const CGFloat GCDiscreetNotificationViewBorderSize = 25; 12 | const CGFloat GCDiscreetNotificationViewPadding = 5; 13 | const CGFloat GCDiscreetNotificationViewHeight = 30; 14 | 15 | NSString* const GCShowAnimation = @"show"; 16 | NSString* const GCHideAnimation = @"hide"; 17 | NSString* const GCChangeProprety = @"changeProprety"; 18 | 19 | NSString* const GCDiscreetNotificationViewTextKey = @"text"; 20 | NSString* const GCDiscreetNotificationViewActivityKey = @"activity"; 21 | 22 | @interface GCDiscreetNotificationView () 23 | 24 | @property (nonatomic, readonly) CGPoint showingCenter; 25 | @property (nonatomic, readonly) CGPoint hidingCenter; 26 | 27 | @property (nonatomic, assign) BOOL animating; 28 | @property (nonatomic, retain) NSDictionary* animationDict; 29 | 30 | - (void) show:(BOOL)animated name:(NSString *)name; 31 | - (void) hide:(BOOL)animated name:(NSString *)name; 32 | - (void) showOrHide:(BOOL) hide animated:(BOOL) animated name:(NSString*) name; 33 | - (void) animationDidStop:(NSString *)animationID finished:(BOOL) finished context:(void *) context; 34 | 35 | - (void) placeOnGrid; 36 | - (void) changePropretyAnimatedWithKeys:(NSArray*) keys values:(NSArray*) values; 37 | 38 | @end 39 | 40 | @implementation GCDiscreetNotificationView 41 | 42 | @synthesize activityIndicator, presentationMode, label; 43 | @synthesize animating, animationDict; 44 | 45 | #pragma mark - 46 | #pragma mark Init and dealloc 47 | 48 | - (id)initWithFrame:(CGRect)frame { 49 | if (self = [super initWithFrame:frame]) { 50 | presentationMode = -1; 51 | } 52 | return self; 53 | } 54 | 55 | - (id) initWithText:(NSString *)text inView:(UIView *)aView { 56 | return [self initWithText:text showActivity:NO inView:aView]; 57 | } 58 | 59 | - (id)initWithText:(NSString*) text showActivity:(BOOL) activity inView:(UIView*) aView { 60 | return [self initWithText:text showActivity:activity inPresentationMode:GCDiscreetNotificationViewPresentationModeTop inView:aView]; 61 | } 62 | 63 | - (id) initWithText:(NSString *)text showActivity:(BOOL)activity 64 | inPresentationMode:(GCDiscreetNotificationViewPresentationMode)aPresentationMode inView:(UIView *)aView { 65 | if ((self = [self initWithFrame:CGRectZero])) { 66 | self.view = aView; 67 | self.textLabel = text; 68 | self.showActivity = activity; 69 | self.presentationMode = aPresentationMode; 70 | 71 | self.center = self.hidingCenter; 72 | [self setNeedsLayout]; 73 | 74 | self.userInteractionEnabled = NO; 75 | self.opaque = NO; 76 | self.backgroundColor = [UIColor clearColor]; 77 | 78 | self.animating = NO; 79 | } 80 | return self; 81 | } 82 | 83 | #pragma mark - 84 | #pragma mark Drawing and layout 85 | 86 | - (void) layoutSubviews { 87 | BOOL withActivity = self.activityIndicator != nil; 88 | CGFloat baseWidth = (2 * GCDiscreetNotificationViewBorderSize) + (withActivity * GCDiscreetNotificationViewPadding); 89 | 90 | CGFloat maxLabelWidth = self.view.frame.size.width - self.activityIndicator.frame.size.width * withActivity - baseWidth; 91 | CGSize maxLabelSize = CGSizeMake(maxLabelWidth, GCDiscreetNotificationViewHeight); 92 | CGFloat textSizeWidth = (self.textLabel != nil) ? [self.textLabel boundingRectWithSize:maxLabelSize options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.label.font} context:nil].size.width : 0; 93 | 94 | CGFloat activityIndicatorWidth = (self.activityIndicator != nil) ? self.activityIndicator.frame.size.width : 0; 95 | CGRect bounds = CGRectMake(0, 0, baseWidth + textSizeWidth + activityIndicatorWidth, GCDiscreetNotificationViewHeight); 96 | if (!CGRectEqualToRect(self.bounds, bounds)) { //The bounds have changed... 97 | self.bounds = bounds; 98 | [self setNeedsDisplay]; 99 | } 100 | 101 | if (self.activityIndicator == nil) self.label.frame = CGRectMake(GCDiscreetNotificationViewBorderSize, 0, textSizeWidth, GCDiscreetNotificationViewHeight); 102 | else { 103 | self.activityIndicator.frame = CGRectMake(GCDiscreetNotificationViewBorderSize, GCDiscreetNotificationViewPadding, self.activityIndicator.frame.size.width, self.activityIndicator.frame.size.height); 104 | self.label.frame = CGRectMake(GCDiscreetNotificationViewBorderSize + GCDiscreetNotificationViewPadding + self.activityIndicator.frame.size.width, 0, textSizeWidth, GCDiscreetNotificationViewHeight); 105 | } 106 | 107 | [self placeOnGrid]; 108 | } 109 | 110 | 111 | - (void) drawRect:(CGRect)rect { 112 | CGRect myFrame = self.bounds; 113 | 114 | CGFloat maxY = 0; 115 | CGFloat minY = 0; 116 | 117 | if (self.presentationMode == GCDiscreetNotificationViewPresentationModeTop) { 118 | maxY = CGRectGetMinY(myFrame) - 1; 119 | minY = CGRectGetMaxY(myFrame); 120 | } 121 | else if (self.presentationMode == GCDiscreetNotificationViewPresentationModeBottom) { 122 | maxY = CGRectGetMaxY(myFrame) + 1; 123 | minY = CGRectGetMinY(myFrame); 124 | } 125 | 126 | CGContextRef context = UIGraphicsGetCurrentContext(); 127 | 128 | CGMutablePathRef path = CGPathCreateMutable(); 129 | CGPathMoveToPoint(path, NULL, CGRectGetMinX(myFrame), maxY); 130 | CGPathAddCurveToPoint(path, NULL, CGRectGetMinX(myFrame) + GCDiscreetNotificationViewBorderSize, maxY, CGRectGetMinX(myFrame), minY, CGRectGetMinX(myFrame) + GCDiscreetNotificationViewBorderSize, minY); 131 | CGPathAddLineToPoint(path, NULL, CGRectGetMaxX(myFrame) - GCDiscreetNotificationViewBorderSize, minY); 132 | CGPathAddCurveToPoint(path, NULL, CGRectGetMaxX(myFrame), minY, CGRectGetMaxX(myFrame) - GCDiscreetNotificationViewBorderSize, maxY, CGRectGetMaxX(myFrame), maxY); 133 | CGPathCloseSubpath(path); 134 | 135 | CGContextSetFillColorWithColor(context, [UIColor colorWithWhite:0.0 alpha:0.8].CGColor); 136 | CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor); 137 | 138 | CGContextAddPath(context, path); 139 | CGContextStrokePath(context); 140 | 141 | CGContextAddPath(context, path); 142 | CGContextFillPath(context); 143 | 144 | CGPathRelease(path); 145 | } 146 | 147 | #pragma mark - 148 | #pragma mark Show/Hide 149 | 150 | - (void)showAnimated { 151 | [self show:YES]; 152 | } 153 | 154 | - (void)hideAnimated { 155 | [self hide:YES]; 156 | } 157 | 158 | - (void) hideAnimatedAfter:(NSTimeInterval) timeInterval { 159 | [self performSelector:@selector(hideAnimated) withObject:nil afterDelay:timeInterval]; 160 | } 161 | 162 | - (void)showAndDismissAutomaticallyAnimated { 163 | [self showAndDismissAfter:1.0]; 164 | } 165 | 166 | - (void)showAndDismissAfter:(NSTimeInterval)timeInterval { 167 | [self showAnimated]; 168 | [self hideAnimatedAfter:timeInterval]; 169 | } 170 | 171 | - (void) show:(BOOL)animated { 172 | [self show:animated name:GCShowAnimation]; 173 | } 174 | 175 | - (void) hide:(BOOL)animated { 176 | [self hide:animated name:GCHideAnimation]; 177 | } 178 | 179 | - (void) show:(BOOL)animated name:(NSString*) name { 180 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideAnimated) object:nil]; 181 | 182 | [self showOrHide:NO animated:animated name:name]; 183 | } 184 | 185 | - (void) hide:(BOOL)animated name:(NSString*) name { 186 | [self showOrHide:YES animated:animated name:name]; 187 | } 188 | 189 | - (void) showOrHide:(BOOL)hide animated:(BOOL)animated name:(NSString *)name { 190 | if ((hide && self.isShowing) || (!hide && !self.isShowing)) { 191 | if (animated) { 192 | self.animating = YES; 193 | [UIView beginAnimations:name context:nil]; 194 | [UIView setAnimationDelegate:self]; 195 | [UIView setAnimationBeginsFromCurrentState:YES]; 196 | [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; 197 | } 198 | 199 | if (hide) self.center = self.hidingCenter; 200 | else { 201 | [self.superview bringSubviewToFront:self]; 202 | [self.activityIndicator startAnimating]; 203 | self.center = self.showingCenter; 204 | self.label.hidden = NO; 205 | } 206 | 207 | [self placeOnGrid]; 208 | 209 | if (animated) [UIView commitAnimations]; 210 | } 211 | } 212 | 213 | #pragma mark - 214 | #pragma mark Animations 215 | 216 | - (void) animationDidStop:(NSString *)animationID finished:(BOOL) finished context:(void *) context { 217 | if (animationID == GCHideAnimation) { 218 | [self.activityIndicator stopAnimating]; 219 | self.label.hidden = YES; 220 | } 221 | else if (animationID == GCChangeProprety) { 222 | NSString* showName = GCShowAnimation; 223 | 224 | for (NSString* key in [self.animationDict allKeys]) { 225 | if (key == GCDiscreetNotificationViewActivityKey) { 226 | self.showActivity = [[self.animationDict objectForKey:key] boolValue]; 227 | } 228 | else if (key == GCDiscreetNotificationViewTextKey) { 229 | self.textLabel = [self.animationDict objectForKey:key]; 230 | } 231 | } 232 | 233 | self.animationDict = nil; 234 | 235 | [self show:YES name:showName]; 236 | } 237 | else if (animationID == GCShowAnimation) { 238 | if (self.animationDict != nil) [self hide:YES name:GCChangeProprety]; 239 | } 240 | 241 | self.animating = NO; 242 | } 243 | 244 | 245 | #pragma mark - 246 | #pragma mark Getter and setters 247 | 248 | - (NSString *) textLabel { 249 | return self.label.text; 250 | } 251 | 252 | - (void) setTextLabel:(NSString *) aText { 253 | self.label.text = aText; 254 | [self setNeedsLayout]; 255 | } 256 | 257 | - (UILabel *)label { 258 | if (label == nil) { 259 | label = [[UILabel alloc] init]; 260 | 261 | label.font = [UIFont boldSystemFontOfSize:15.0]; 262 | label.textColor = [UIColor whiteColor]; 263 | label.shadowColor = [UIColor blackColor]; 264 | label.shadowOffset = CGSizeMake(0, 1); 265 | label.baselineAdjustment = UIBaselineAdjustmentAlignCenters; 266 | label.backgroundColor = [UIColor clearColor]; 267 | 268 | [self addSubview:label]; 269 | } 270 | return label; 271 | } 272 | 273 | - (BOOL) showActivity { 274 | return (self.activityIndicator != nil); 275 | } 276 | 277 | - (void) setShowActivity:(BOOL) activity { 278 | if (activity != self.showActivity) { 279 | if (activity) { 280 | activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 281 | [self addSubview:activityIndicator]; 282 | } 283 | else { 284 | [activityIndicator removeFromSuperview]; 285 | activityIndicator = nil; 286 | } 287 | 288 | [self setNeedsLayout]; 289 | } 290 | } 291 | 292 | - (void) setView:(UIView *) aView { 293 | if (self.view != aView) { 294 | [self removeFromSuperview]; 295 | 296 | [aView addSubview:self]; 297 | [self setNeedsLayout]; 298 | } 299 | } 300 | 301 | - (UIView *)view { 302 | return self.superview; 303 | } 304 | 305 | - (void) setPresentationMode:(GCDiscreetNotificationViewPresentationMode) newPresentationMode { 306 | if (presentationMode != newPresentationMode) { 307 | BOOL showing = self.isShowing; 308 | 309 | presentationMode = newPresentationMode; 310 | if (presentationMode == GCDiscreetNotificationViewPresentationModeTop) { 311 | self.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin; 312 | } 313 | else if (presentationMode == GCDiscreetNotificationViewPresentationModeBottom) { 314 | self.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin; 315 | } 316 | 317 | self.center = showing ? self.showingCenter : self.hidingCenter; 318 | 319 | [self setNeedsDisplay]; 320 | [self placeOnGrid]; 321 | } 322 | } 323 | 324 | - (BOOL) isShowing { 325 | return (self.center.y == self.showingCenter.y); 326 | } 327 | 328 | - (CGPoint) showingCenter { 329 | CGFloat y = 0; 330 | if (self.presentationMode == GCDiscreetNotificationViewPresentationModeTop) y = 15; 331 | else if (self.presentationMode == GCDiscreetNotificationViewPresentationModeBottom) y = self.view.bounds.size.height - 15; 332 | return CGPointMake(self.view.bounds.size.width / 2, y); 333 | } 334 | 335 | - (CGPoint) hidingCenter { 336 | CGFloat y = 0; 337 | if (self.presentationMode == GCDiscreetNotificationViewPresentationModeTop) y = - 15; 338 | else if (self.presentationMode == GCDiscreetNotificationViewPresentationModeBottom) y = 15 + self.view.bounds.size.height; 339 | return CGPointMake(self.view.bounds.size.width / 2, y); 340 | } 341 | 342 | #pragma mark - 343 | #pragma mark Animated Setters 344 | 345 | - (void) setTextLabel:(NSString *)aText animated:(BOOL)animated { 346 | if (animated && (self.showing || self.animating)) { 347 | [self changePropretyAnimatedWithKeys:[NSArray arrayWithObject:GCDiscreetNotificationViewTextKey] 348 | values:[NSArray arrayWithObject:aText]]; 349 | } 350 | else self.textLabel = aText; 351 | } 352 | 353 | - (void) setShowActivity:(BOOL)activity animated:(BOOL)animated { 354 | if (animated && (self.showing || self.animating)) { 355 | [self changePropretyAnimatedWithKeys:[NSArray arrayWithObject:GCDiscreetNotificationViewActivityKey] 356 | values:[NSArray arrayWithObject:[NSNumber numberWithBool:activity]]]; 357 | } 358 | else self.showActivity = activity; 359 | } 360 | 361 | - (void) setTextLabel:(NSString *)aText andSetShowActivity:(BOOL)activity animated:(BOOL)animated { 362 | if (animated && (self.showing || self.animating)) { 363 | [self changePropretyAnimatedWithKeys:[NSArray arrayWithObjects:GCDiscreetNotificationViewTextKey, GCDiscreetNotificationViewActivityKey, nil] 364 | values:[NSArray arrayWithObjects:aText, [NSNumber numberWithBool:activity], nil]]; 365 | } 366 | else { 367 | self.textLabel = aText; 368 | self.showActivity = activity; 369 | } 370 | } 371 | 372 | #pragma mark - 373 | #pragma mark Helper Methods 374 | 375 | - (void) placeOnGrid { 376 | CGRect frame = self.frame; 377 | 378 | frame.origin.x = roundf(frame.origin.x); 379 | frame.origin.y = roundf(frame.origin.y); 380 | 381 | self.frame = frame; 382 | } 383 | 384 | - (void) changePropretyAnimatedWithKeys:(NSArray*) keys values:(NSArray*) values { 385 | NSDictionary* newDict = [NSDictionary dictionaryWithObjects:values forKeys:keys]; 386 | 387 | if (self.animationDict == nil) { 388 | self.animationDict = newDict; 389 | } 390 | else { 391 | NSMutableDictionary* mutableAnimationDict = [self.animationDict mutableCopy]; 392 | [mutableAnimationDict addEntriesFromDictionary:newDict]; 393 | self.animationDict = mutableAnimationDict; 394 | } 395 | 396 | if (!self.animating) [self hide:YES name:GCChangeProprety]; 397 | } 398 | 399 | #pragma mark - UIView subclass 400 | 401 | - (void)willMoveToSuperview:(UIView *)newSuperview { 402 | if (newSuperview == nil) { 403 | self.animationDict = nil; 404 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideAnimated) object:nil]; 405 | } 406 | } 407 | 408 | @end 409 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | This control is dual licensed: 2 | 3 | You can use it for free under the MIT licence below or, if you require non-attribution you can purchase the commercial licence available at http://www.cocoacontrols.com/authors/gcamp 4 | 5 | --- 6 | 7 | Copyright (c) 2011 Guillaume Campagna 8 | 9 | Permission is hereby granted, free of charge, to any person 10 | obtaining a copy of this software and associated documentation 11 | files (the "Software"), to deal in the Software without 12 | restriction, including without limitation the rights to use, 13 | copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the 15 | Software is furnished to do so, subject to the following 16 | conditions: 17 | 18 | The above copyright notice and this permission notice shall be 19 | included in all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 23 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. GCDiscreetNotificationView 2 | 3 | GCDiscreetNotificationView is a discreet, non-modal, notification view for iOS. You can use it to show an activity or state of you app without blocking the user interactions. 4 | 5 | !http://i.imgur.com/8vcti5u.png! 6 | 7 | GCDiscreetNotificationView features: 8 | 9 | * Easy to use : init and show 10 | * Can show an activity indicator 11 | * Two presentation mode (top and bottom) 12 | * All properties (text, activity and presentation mode) can be changed in a animated fashion 13 | 14 | h2. Usage 15 | 16 | (See the demo project included) 17 | 18 | You simply allocate the notification view with one of the following methods. 19 | 20 | The parameters are the following : 21 | * _text_ : the text presented on the notification 22 | * _activity_ : if set to @YES@, the notification with show a activity indicator 23 | * _aPresentationMode_ : the presentation mode of the notification (top or bottom) 24 | * _aView_ : the view that will contain the notification. The view should be able to accept subviews (will not work on a @UITableView@ for example) 25 | 26 |
27 | - (id) initWithText:(NSString *)text inView:(UIView *)aView;
28 | - (id) initWithText:(NSString *)text showActivity:(BOOL)activity inView:(UIView *)aView;
29 | - (id) initWithText:(NSString *)text showActivity:(BOOL)activity inPresentationMode:(GCDiscreetNotificationViewPresentationMode) aPresentationMode inView:(UIView *)aView;
30 | 
31 | 32 | You show or hide the notification with these methods. The @showAndDismissAutomaticallyAnimated@ will hide your notification automatically after 1 second. 33 | 34 |
35 | - (void) showAnimated;
36 | - (void) hideAnimated;
37 | - (void) hideAnimatedAfter:(NSTimeInterval) timeInterval;
38 | - (void) show:(BOOL) animated;
39 | - (void) hide:(BOOL) animated;
40 | - (void) showAndDismissAutomaticallyAnimated;
41 | - (void) showAndDismissAfter:(NSTimeInterval) timeInterval;
42 | 
43 | 44 | You can change the text of the label of the activity viewing at any moment with these properties. 45 | 46 |
47 | @property (nonatomic, assign) UIView *view;
48 | @property (nonatomic, assign) GCDiscreetNotificationViewPresentationMode presentationMode;
49 | @property (nonatomic, copy) NSString* textLabel;
50 | @property (nonatomic, assign) BOOL showActivity;
51 | 
52 | 53 | These properties can be changed in a animated fashion (except the view). 54 | 55 |
56 | - (void) setTextLabel:(NSString *) aText animated:(BOOL) animated;
57 | - (void) setShowActivity:(BOOL) activity animated:(BOOL) animated;
58 | - (void) setTextLabel:(NSString *)aText andSetShowActivity:(BOOL)activity animated:(BOOL)animated;
59 | - (void) setPresentationMode:(GCDiscreetNotificationViewPresentationMode) newPresentationMode animated:(BOOL) animated;
60 | 
61 | 62 | You can access directly the notification's label and activity indicator. And change some propreties on that label and activity indicator. If you want to change the label's text or hide the indicator, use @textLabel@ or @showActivity@ instead. 63 | 64 |
65 | @property (nonatomic, retain, readonly) UILabel *label;  
66 | @property (nonatomic, retain, readonly) UIActivityIndicatorView *activityIndicator;
67 | 
68 | --------------------------------------------------------------------------------