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