├── .gitignore ├── Classes ├── NMViewControllerAppDelegate.h ├── NMViewControllerAppDelegate.m ├── SwitchTabBar.h ├── SwitchTabBar.m ├── SwitchTabBar.xib ├── TabOneController.h ├── TabOneController.m ├── TabOneController.xib ├── TabThreeController.h ├── TabThreeController.m ├── TabThreeController.xib ├── TabTwoController.h ├── TabTwoController.m └── TabTwoController.xib ├── Libraries ├── NMView │ ├── NMView.h │ ├── NMView.m │ ├── NMViewLayout.h │ ├── NMViewLayout.m │ ├── NMViewLayoutOmitSubviewsView.h │ ├── NMViewLayoutOmitSubviewsView.m │ ├── NMViewLayoutView.h │ ├── NMViewLayoutView.m │ ├── UIImage+NMNSCoding.h │ ├── UIImage+NMNSCoding.m │ ├── UIView+NMTemplating.h │ └── UIView+NMTemplating.m └── NMViewController │ ├── NMNavigationBar.h │ ├── NMNavigationBar.m │ ├── NMNavigationController.h │ ├── NMNavigationController.m │ ├── NMNavigationController.xib │ ├── NMTabBar.h │ ├── NMTabBar.m │ ├── NMTabBarController.h │ ├── NMTabBarController.m │ ├── NMTabBarController.xib │ ├── NMUINavigationBar.h │ ├── NMUINavigationBar.m │ ├── NMUITabBar.h │ ├── NMUITabBar.m │ ├── NMViewController.h │ └── NMViewController.m ├── NMViewController.xcodeproj └── project.pbxproj ├── NMViewController_Prefix.pch ├── README.markdown ├── Resources ├── Icon-72.png ├── Icon-Small-50.png ├── Icon-Small.png ├── Localizable.strings ├── MainWindow.xib ├── NMViewController-Info.plist ├── UnitTests-Info.plist └── iTunesArtwork ├── UnitTests ├── TestSuite.h └── TestSuite.m └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Build folder 2 | build 3 | 4 | # User-specific files 5 | *.pbxuser 6 | *.mode1v3 7 | 8 | # Mac OS X 9 | .DS_Store 10 | -------------------------------------------------------------------------------- /Classes/NMViewControllerAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewControllerAppDelegate.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "NMNavigationController.h" 12 | #import "NMTabBarController.h" 13 | 14 | 15 | @interface NMViewControllerAppDelegate : NSObject { 16 | 17 | UIWindow *window; 18 | 19 | NMTabBarController *nmTabBarController; 20 | NMNavigationController *nmNavigationController; 21 | UIViewController *tabOneController; 22 | UIViewController *tabTwoController; 23 | UIViewController *tabThreeController; 24 | 25 | UITabBarController *tabBarController; 26 | UINavigationController *navigationController; 27 | 28 | } 29 | 30 | @property (nonatomic, retain) IBOutlet UIWindow *window; 31 | @property (nonatomic, retain) IBOutlet NMTabBarController *nmTabBarController; 32 | @property (nonatomic, retain) IBOutlet NMNavigationController *nmNavigationController; 33 | @property (nonatomic, retain) IBOutlet UIViewController *tabOneController; 34 | @property (nonatomic, retain) IBOutlet UIViewController *tabTwoController; 35 | @property (nonatomic, retain) IBOutlet UIViewController *tabThreeController; 36 | 37 | @end 38 | 39 | -------------------------------------------------------------------------------- /Classes/NMViewControllerAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewControllerAppDelegate.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | #import "NMViewControllerAppDelegate.h" 10 | 11 | #import "NMUINavigationBar.h" 12 | #import "NMUITabBar.h" 13 | #import "SwitchTabBar.h" 14 | 15 | 16 | 17 | @implementation NMViewControllerAppDelegate 18 | 19 | #pragma mark Properties 20 | 21 | @synthesize window, nmTabBarController, nmNavigationController, tabOneController, tabTwoController, tabThreeController; 22 | 23 | 24 | #pragma mark Application lifecycle 25 | 26 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 27 | // setup controller titles 28 | tabOneController.title = @"First"; 29 | tabTwoController.title = @"Second"; 30 | tabThreeController.title = @"Third"; 31 | 32 | // setup of NMTabBarController before view is loaded 33 | #ifdef UITABBAR 34 | nmTabBarController.tabBar = [[[NMUITabBar alloc] init] autorelease]; 35 | 36 | nmNavigationController.navigationBar = [[[NMUINavigationBar alloc] init] autorelease]; 37 | [nmNavigationController pushViewController:tabOneController animated:NO]; 38 | [window addSubview:nmNavigationController.view]; 39 | [self performSelector:@selector(nmPushVC:) withObject:tabTwoController afterDelay:5]; 40 | 41 | //navigationController = [[UINavigationController alloc] initWithRootViewController:tabOneController]; 42 | //[window addSubview:navigationController.view]; 43 | //[self performSelector:@selector(pushVC:) withObject:tabTwoController afterDelay:5]; 44 | #elif SWITCHTABBAR 45 | nmTabBarController.tabBar = [[[SwitchTabBar alloc] init] autorelease]; 46 | #endif 47 | 48 | nmTabBarController.viewControllers = [NSArray arrayWithObjects:tabOneController, tabTwoController, nil]; 49 | [window addSubview:nmTabBarController.view]; 50 | 51 | //tabBarController = [[UITabBarController alloc] init]; 52 | //tabBarController.viewControllers = nmTabBarController.viewControllers; 53 | //[window addSubview:tabBarController.view]; 54 | 55 | //nmNavigationController.navigationBar = [[[NMUINavigationBar alloc] init] autorelease]; 56 | //[nmNavigationController pushViewController:tabOneController animated:NO]; 57 | //[window addSubview:nmNavigationController.view]; 58 | //[self performSelector:@selector(nmPushVC:) withObject:tabTwoController afterDelay:5]; 59 | 60 | //navigationController = [[UINavigationController alloc] initWithRootViewController:tabOneController]; 61 | //[window addSubview:navigationController.view]; 62 | //[self performSelector:@selector(pushVC:) withObject:tabTwoController afterDelay:5]; 63 | 64 | [window makeKeyAndVisible]; 65 | 66 | 67 | //UITapGestureRecognizer *r = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap)] autorelease]; 68 | //r.numberOfTapsRequired = 2; 69 | //[window addGestureRecognizer:r]; 70 | 71 | 72 | return YES; 73 | } 74 | 75 | 76 | - (void)nmPushVC:(UIViewController *)vc { 77 | [nmNavigationController pushViewController:vc animated:YES]; 78 | /*if (vc == tabTwoController) { 79 | [self performSelector:_cmd withObject:tabThreeController afterDelay:5]; 80 | }*/ 81 | } 82 | 83 | - (void)pushVC:(UIViewController *)vc { 84 | [navigationController pushViewController:vc animated:YES]; 85 | /*if (vc == tabTwoController) { 86 | [self performSelector:_cmd withObject:tabThreeController afterDelay:5]; 87 | }*/ 88 | } 89 | 90 | 91 | - (void)logNavController { 92 | NSLog(@"tabOne. navVC: %@", tabOneController.navigationController); 93 | NSLog(@"tabOne. nmNavVC: %@", tabOneController.nmNavigationController); 94 | } 95 | 96 | 97 | - (void)doubleTap { 98 | /*[navigationController setViewControllers:[NSArray arrayWithObjects:tabOneController, tabThreeController, nil] 99 | animated:YES];*/ 100 | nmNavigationController.topViewController = tabThreeController; 101 | } 102 | 103 | 104 | #pragma mark Tab Bar Controller Delegate 105 | 106 | - (void)tabBarController:(NMTabBarController *)vc willSelectIndex:(NSUInteger)tab { 107 | NSLog(@"willSelect: %d", tab); 108 | } 109 | 110 | - (void)tabBarController:(NMTabBarController *)vc didSelectIndex:(NSUInteger)tab { 111 | NSLog(@"didSelect: %d", tab); 112 | } 113 | 114 | - (void)tabBarController:(NMTabBarController *)vc popToRoot:(NSUInteger)tab { 115 | NSLog(@"popToRoot: %d", tab); 116 | } 117 | 118 | 119 | - (void)dealloc { 120 | [tabOneController release]; 121 | [tabTwoController release]; 122 | [tabThreeController release]; 123 | [nmNavigationController release]; 124 | [nmTabBarController release]; 125 | [window release]; 126 | [super dealloc]; 127 | } 128 | 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /Classes/SwitchTabBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMWeirdTabBar.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "NMTabBar.h" 12 | #import "SwitchTabBar.h" 13 | 14 | 15 | @interface SwitchTabBar : NMTabBar { 16 | 17 | UISwitch *tabSwitch; 18 | 19 | } 20 | 21 | @property (nonatomic, retain) IBOutlet UISwitch *tabSwitch; 22 | 23 | - (IBAction)switchChangedValue; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Classes/SwitchTabBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMWeirdTabBar.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | #import "SwitchTabBar.h" 10 | 11 | 12 | @implementation SwitchTabBar 13 | 14 | @synthesize tabSwitch; 15 | 16 | 17 | - (void)setSelectedTab:(NSUInteger)tabIndex { 18 | if (tabIndex == 0) tabSwitch.on = YES; 19 | else tabSwitch.on = NO; 20 | } 21 | 22 | 23 | - (IBAction)switchChangedValue { 24 | [delegate tabBar:self didSelectTab:(tabSwitch.on ? 0 : 1)]; 25 | } 26 | 27 | 28 | - (void)dealloc { 29 | self.tabSwitch = nil; 30 | 31 | [super dealloc]; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Classes/SwitchTabBar.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1056 5 | 10J4138 6 | 823 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 132 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 | IBIPadFramework 35 | 36 | 37 | IBFirstResponder 38 | IBIPadFramework 39 | 40 | 41 | 42 | 292 43 | 44 | YES 45 | 46 | 47 | 269 48 | {{337, 53}, {94, 27}} 49 | 50 | NO 51 | IBIPadFramework 52 | 0 53 | 0 54 | YES 55 | 56 | 57 | 58 | 290 59 | {{20, 20}, {728, 21}} 60 | 61 | NO 62 | YES 63 | 7 64 | NO 65 | IBIPadFramework 66 | I'm the SwitchTabBar. Use switch to change current Tab 67 | 68 | 1 69 | MCAwIDAAA 70 | 71 | 72 | 3 73 | MQA 74 | 75 | 1 76 | 10 77 | 1 78 | 79 | 80 | {768, 100} 81 | 82 | 83 | 1 84 | MSAwLjUgMAA 85 | 86 | IBIPadFramework 87 | 88 | 89 | 90 | 91 | YES 92 | 93 | 94 | switchChangedValue 95 | 96 | 97 | 13 98 | 99 | 5 100 | 101 | 102 | 103 | tabSwitch 104 | 105 | 106 | 107 | 6 108 | 109 | 110 | 111 | 112 | YES 113 | 114 | 0 115 | 116 | 117 | 118 | 119 | 120 | -1 121 | 122 | 123 | File's Owner 124 | 125 | 126 | -2 127 | 128 | 129 | 130 | 131 | 2 132 | 133 | 134 | YES 135 | 136 | 137 | 138 | 139 | 140 | 141 | 3 142 | 143 | 144 | 145 | 146 | 7 147 | 148 | 149 | 150 | 151 | 152 | 153 | YES 154 | 155 | YES 156 | -1.CustomClassName 157 | -2.CustomClassName 158 | 2.IBEditorWindowLastContentRect 159 | 2.IBPluginDependency 160 | 3.IBPluginDependency 161 | 3.IBViewBoundsToFrameTransform 162 | 7.IBPluginDependency 163 | 7.IBViewBoundsToFrameTransform 164 | 165 | 166 | YES 167 | SwitchTabBar 168 | UIResponder 169 | {{320, 733}, {768, 100}} 170 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 171 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 172 | 173 | P4AAAL+AAABDqIAAwnYAAA 174 | 175 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 176 | 177 | P4AAAL+AAABBoAAAwmgAAA 178 | 179 | 180 | 181 | 182 | YES 183 | 184 | 185 | YES 186 | 187 | 188 | 189 | 190 | YES 191 | 192 | 193 | YES 194 | 195 | 196 | 197 | 7 198 | 199 | 200 | 201 | YES 202 | 203 | NMTabBar 204 | NMView 205 | 206 | delegate 207 | id 208 | 209 | 210 | delegate 211 | 212 | delegate 213 | id 214 | 215 | 216 | 217 | IBProjectSource 218 | Libraries/NMViewController/NMTabBar.h 219 | 220 | 221 | 222 | NMView 223 | UIView 224 | 225 | IBProjectSource 226 | Libraries/NMView/NMView.h 227 | 228 | 229 | 230 | SwitchTabBar 231 | NMTabBar 232 | 233 | switchChangedValue 234 | id 235 | 236 | 237 | switchChangedValue 238 | 239 | switchChangedValue 240 | id 241 | 242 | 243 | 244 | tabSwitch 245 | UISwitch 246 | 247 | 248 | tabSwitch 249 | 250 | tabSwitch 251 | UISwitch 252 | 253 | 254 | 255 | IBProjectSource 256 | Classes/SwitchTabBar.h 257 | 258 | 259 | 260 | UIView 261 | 262 | IBProjectSource 263 | Libraries/NMView/UIView+NMTemplating.h 264 | 265 | 266 | 267 | 268 | YES 269 | 270 | NSObject 271 | 272 | IBFrameworkSource 273 | Foundation.framework/Headers/NSError.h 274 | 275 | 276 | 277 | NSObject 278 | 279 | IBFrameworkSource 280 | Foundation.framework/Headers/NSFileManager.h 281 | 282 | 283 | 284 | NSObject 285 | 286 | IBFrameworkSource 287 | Foundation.framework/Headers/NSKeyValueCoding.h 288 | 289 | 290 | 291 | NSObject 292 | 293 | IBFrameworkSource 294 | Foundation.framework/Headers/NSKeyValueObserving.h 295 | 296 | 297 | 298 | NSObject 299 | 300 | IBFrameworkSource 301 | Foundation.framework/Headers/NSKeyedArchiver.h 302 | 303 | 304 | 305 | NSObject 306 | 307 | IBFrameworkSource 308 | Foundation.framework/Headers/NSObject.h 309 | 310 | 311 | 312 | NSObject 313 | 314 | IBFrameworkSource 315 | Foundation.framework/Headers/NSRunLoop.h 316 | 317 | 318 | 319 | NSObject 320 | 321 | IBFrameworkSource 322 | Foundation.framework/Headers/NSThread.h 323 | 324 | 325 | 326 | NSObject 327 | 328 | IBFrameworkSource 329 | Foundation.framework/Headers/NSURL.h 330 | 331 | 332 | 333 | NSObject 334 | 335 | IBFrameworkSource 336 | Foundation.framework/Headers/NSURLConnection.h 337 | 338 | 339 | 340 | NSObject 341 | 342 | IBFrameworkSource 343 | UIKit.framework/Headers/UIAccessibility.h 344 | 345 | 346 | 347 | NSObject 348 | 349 | IBFrameworkSource 350 | UIKit.framework/Headers/UINibLoading.h 351 | 352 | 353 | 354 | NSObject 355 | 356 | IBFrameworkSource 357 | UIKit.framework/Headers/UIResponder.h 358 | 359 | 360 | 361 | UIControl 362 | UIView 363 | 364 | IBFrameworkSource 365 | UIKit.framework/Headers/UIControl.h 366 | 367 | 368 | 369 | UILabel 370 | UIView 371 | 372 | IBFrameworkSource 373 | UIKit.framework/Headers/UILabel.h 374 | 375 | 376 | 377 | UIResponder 378 | NSObject 379 | 380 | 381 | 382 | UISwitch 383 | UIControl 384 | 385 | IBFrameworkSource 386 | UIKit.framework/Headers/UISwitch.h 387 | 388 | 389 | 390 | UIView 391 | 392 | IBFrameworkSource 393 | UIKit.framework/Headers/UIPrintFormatter.h 394 | 395 | 396 | 397 | UIView 398 | 399 | IBFrameworkSource 400 | UIKit.framework/Headers/UITextField.h 401 | 402 | 403 | 404 | UIView 405 | UIResponder 406 | 407 | IBFrameworkSource 408 | UIKit.framework/Headers/UIView.h 409 | 410 | 411 | 412 | 413 | 0 414 | IBIPadFramework 415 | 416 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 417 | 418 | 419 | 420 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 421 | 422 | 423 | YES 424 | ../NMViewController.xcodeproj 425 | 3 426 | 132 427 | 428 | 429 | -------------------------------------------------------------------------------- /Classes/TabOneController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TabOneController.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "NMViewController.h" 12 | 13 | 14 | @interface TabOneController : NMViewController { 15 | 16 | UILabel *titleLabel; 17 | 18 | } 19 | 20 | @property (nonatomic, retain) IBOutlet UILabel *titleLabel; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Classes/TabOneController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TabOneController.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | #import "TabOneController.h" 10 | 11 | #import "NMNavigationController.h" 12 | 13 | 14 | @implementation TabOneController 15 | 16 | @synthesize titleLabel; 17 | 18 | 19 | - (void)logView:(NSString *)prefix animated:(BOOL)animated { 20 | NSLog(@"-----"); 21 | NSLog(@"%@ (animated: %@)", prefix, (animated ? @"YES" : @"NO")); 22 | NSLog(@"isLoaded? %@", ([self isViewLoaded] ? @"YES" : @"NO")); 23 | NSLog(@"navVC: %@", self.navigationController); 24 | NSLog(@"nmNavVC: %@", self.nmNavigationController); 25 | NSLog(@"child controller: %@", self.nmNavigationController.childViewControllers); 26 | 27 | if ([self isViewLoaded]) { 28 | NSLog(@"superview: %@", self.view.superview); 29 | NSLog(@"frame: %@", NSStringFromCGRect(self.view.frame)); 30 | } 31 | } 32 | 33 | 34 | - (void)viewWillAppear:(BOOL)animated { 35 | [super viewWillAppear:animated]; 36 | [self logView:@"willAppear" animated:animated]; 37 | } 38 | 39 | - (void)viewDidAppear:(BOOL)animated { 40 | [super viewDidAppear:animated]; 41 | [self logView:@"didAppear" animated:animated]; 42 | } 43 | 44 | - (void)viewWillDisappear:(BOOL)animated { 45 | [super viewWillDisappear:animated]; 46 | [self logView:@"willDisappear" animated:animated]; 47 | } 48 | 49 | - (void)viewDidDisappear:(BOOL)animated { 50 | [super viewDidDisappear:animated]; 51 | [self logView:@"didDisappear" animated:animated]; 52 | } 53 | 54 | 55 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 56 | // Overriden to allow any orientation. 57 | NSLog(@"-----"); 58 | NSLog(@"shouldAutorotate"); 59 | return YES; 60 | } 61 | 62 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 63 | NSLog(@"-----"); 64 | NSLog(@"willAnimate"); 65 | } 66 | 67 | - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { 68 | NSLog(@"-----"); 69 | NSLog(@"didRotate"); 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /Classes/TabOneController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1056 5 | 10J4138 6 | 823 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 132 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 | IBIPadFramework 35 | 36 | 37 | IBFirstResponder 38 | IBIPadFramework 39 | 40 | 41 | 42 | 292 43 | 44 | YES 45 | 46 | 47 | 274 48 | {{20, 66}, {728, 918}} 49 | 50 | 51 | 1 52 | MC40NjY2NjY2NjY3IDAuNzU2ODYyNzQ1MSAwLjMwNTg4MjM1MjkAA 53 | 54 | IBIPadFramework 55 | 56 | 57 | 58 | 290 59 | {{20, 20}, {728, 21}} 60 | 61 | NO 62 | YES 63 | 7 64 | NO 65 | IBIPadFramework 66 | The grey area is occupied by the controller hosted in the tab. Green is contained within. 67 | 68 | 1 69 | MCAwIDAAA 70 | 71 | 72 | 3 73 | MQA 74 | 75 | 1 76 | 10 77 | 1 78 | 79 | 80 | {768, 1004} 81 | 82 | 83 | 1 84 | MC45MTM3MjU0OTAyIDAuOTE3NjQ3MDU4OCAwLjkyMTU2ODYyNzUAA 85 | 86 | NO 87 | 88 | 2 89 | 90 | IBIPadFramework 91 | 92 | 93 | 94 | 95 | YES 96 | 97 | 98 | view 99 | 100 | 101 | 102 | 3 103 | 104 | 105 | 106 | titleLabel 107 | 108 | 109 | 110 | 6 111 | 112 | 113 | 114 | 115 | YES 116 | 117 | 0 118 | 119 | 120 | 121 | 122 | 123 | -1 124 | 125 | 126 | File's Owner 127 | 128 | 129 | -2 130 | 131 | 132 | 133 | 134 | 2 135 | 136 | 137 | YES 138 | 139 | 140 | 141 | 142 | 143 | 144 | 4 145 | 146 | 147 | 148 | 149 | 5 150 | 151 | 152 | 153 | 154 | 155 | 156 | YES 157 | 158 | YES 159 | -1.CustomClassName 160 | -2.CustomClassName 161 | 2.IBEditorWindowLastContentRect 162 | 2.IBPluginDependency 163 | 4.IBPluginDependency 164 | 5.IBPluginDependency 165 | 166 | 167 | YES 168 | TabOneController 169 | UIResponder 170 | {{352, 0}, {783, 856}} 171 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 172 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 173 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 174 | 175 | 176 | 177 | YES 178 | 179 | 180 | YES 181 | 182 | 183 | 184 | 185 | YES 186 | 187 | 188 | YES 189 | 190 | 191 | 192 | 6 193 | 194 | 195 | 196 | YES 197 | 198 | NMViewController 199 | UIViewController 200 | 201 | IBProjectSource 202 | Libraries/NMViewController/NMViewController.h 203 | 204 | 205 | 206 | TabOneController 207 | NMViewController 208 | 209 | titleLabel 210 | UILabel 211 | 212 | 213 | titleLabel 214 | 215 | titleLabel 216 | UILabel 217 | 218 | 219 | 220 | IBProjectSource 221 | Classes/TabOneController.h 222 | 223 | 224 | 225 | UIView 226 | 227 | IBProjectSource 228 | Libraries/NMView/UIView+NMTemplating.h 229 | 230 | 231 | 232 | 233 | YES 234 | 235 | NSObject 236 | 237 | IBFrameworkSource 238 | Foundation.framework/Headers/NSError.h 239 | 240 | 241 | 242 | NSObject 243 | 244 | IBFrameworkSource 245 | Foundation.framework/Headers/NSFileManager.h 246 | 247 | 248 | 249 | NSObject 250 | 251 | IBFrameworkSource 252 | Foundation.framework/Headers/NSKeyValueCoding.h 253 | 254 | 255 | 256 | NSObject 257 | 258 | IBFrameworkSource 259 | Foundation.framework/Headers/NSKeyValueObserving.h 260 | 261 | 262 | 263 | NSObject 264 | 265 | IBFrameworkSource 266 | Foundation.framework/Headers/NSKeyedArchiver.h 267 | 268 | 269 | 270 | NSObject 271 | 272 | IBFrameworkSource 273 | Foundation.framework/Headers/NSObject.h 274 | 275 | 276 | 277 | NSObject 278 | 279 | IBFrameworkSource 280 | Foundation.framework/Headers/NSRunLoop.h 281 | 282 | 283 | 284 | NSObject 285 | 286 | IBFrameworkSource 287 | Foundation.framework/Headers/NSThread.h 288 | 289 | 290 | 291 | NSObject 292 | 293 | IBFrameworkSource 294 | Foundation.framework/Headers/NSURL.h 295 | 296 | 297 | 298 | NSObject 299 | 300 | IBFrameworkSource 301 | Foundation.framework/Headers/NSURLConnection.h 302 | 303 | 304 | 305 | NSObject 306 | 307 | IBFrameworkSource 308 | UIKit.framework/Headers/UIAccessibility.h 309 | 310 | 311 | 312 | NSObject 313 | 314 | IBFrameworkSource 315 | UIKit.framework/Headers/UINibLoading.h 316 | 317 | 318 | 319 | NSObject 320 | 321 | IBFrameworkSource 322 | UIKit.framework/Headers/UIResponder.h 323 | 324 | 325 | 326 | UILabel 327 | UIView 328 | 329 | IBFrameworkSource 330 | UIKit.framework/Headers/UILabel.h 331 | 332 | 333 | 334 | UIResponder 335 | NSObject 336 | 337 | 338 | 339 | UISearchBar 340 | UIView 341 | 342 | IBFrameworkSource 343 | UIKit.framework/Headers/UISearchBar.h 344 | 345 | 346 | 347 | UISearchDisplayController 348 | NSObject 349 | 350 | IBFrameworkSource 351 | UIKit.framework/Headers/UISearchDisplayController.h 352 | 353 | 354 | 355 | UIView 356 | 357 | IBFrameworkSource 358 | UIKit.framework/Headers/UIPrintFormatter.h 359 | 360 | 361 | 362 | UIView 363 | 364 | IBFrameworkSource 365 | UIKit.framework/Headers/UITextField.h 366 | 367 | 368 | 369 | UIView 370 | UIResponder 371 | 372 | IBFrameworkSource 373 | UIKit.framework/Headers/UIView.h 374 | 375 | 376 | 377 | UIViewController 378 | 379 | IBFrameworkSource 380 | UIKit.framework/Headers/UINavigationController.h 381 | 382 | 383 | 384 | UIViewController 385 | 386 | IBFrameworkSource 387 | UIKit.framework/Headers/UIPopoverController.h 388 | 389 | 390 | 391 | UIViewController 392 | 393 | IBFrameworkSource 394 | UIKit.framework/Headers/UISplitViewController.h 395 | 396 | 397 | 398 | UIViewController 399 | 400 | IBFrameworkSource 401 | UIKit.framework/Headers/UITabBarController.h 402 | 403 | 404 | 405 | UIViewController 406 | UIResponder 407 | 408 | IBFrameworkSource 409 | UIKit.framework/Headers/UIViewController.h 410 | 411 | 412 | 413 | 414 | 0 415 | IBIPadFramework 416 | 417 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 418 | 419 | 420 | 421 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 422 | 423 | 424 | YES 425 | ../NMViewController.xcodeproj 426 | 3 427 | 132 428 | 429 | 430 | -------------------------------------------------------------------------------- /Classes/TabThreeController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TabThreeController.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 29.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface TabThreeController : UIViewController { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Classes/TabThreeController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TabThreeController.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 29.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | #import "TabThreeController.h" 10 | 11 | 12 | @implementation TabThreeController 13 | 14 | // The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad. 15 | /* 16 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 17 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 18 | if (self) { 19 | // Custom initialization. 20 | } 21 | return self; 22 | } 23 | */ 24 | 25 | /* 26 | // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | } 30 | */ 31 | 32 | 33 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 34 | // Overriden to allow any orientation. 35 | return YES; 36 | } 37 | 38 | 39 | - (void)didReceiveMemoryWarning { 40 | // Releases the view if it doesn't have a superview. 41 | [super didReceiveMemoryWarning]; 42 | 43 | // Release any cached data, images, etc. that aren't in use. 44 | } 45 | 46 | 47 | - (void)viewDidUnload { 48 | [super viewDidUnload]; 49 | // Release any retained subviews of the main view. 50 | // e.g. self.myOutlet = nil; 51 | } 52 | 53 | 54 | - (void)dealloc { 55 | [super dealloc]; 56 | } 57 | 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Classes/TabThreeController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1056 5 | 10J4138 6 | 823 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 132 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 | IBIPadFramework 35 | 36 | 37 | IBFirstResponder 38 | IBIPadFramework 39 | 40 | 41 | 42 | 292 43 | {768, 1004} 44 | 45 | 46 | 1 47 | MC4xNTI5NDExNzY1IDAuMjE1Njg2Mjc0NSAwLjU2MDc4NDMxMzcAA 48 | 49 | NO 50 | 51 | 2 52 | 53 | IBIPadFramework 54 | 55 | 56 | 57 | 58 | YES 59 | 60 | 61 | view 62 | 63 | 64 | 65 | 3 66 | 67 | 68 | 69 | 70 | YES 71 | 72 | 0 73 | 74 | 75 | 76 | 77 | 78 | -1 79 | 80 | 81 | File's Owner 82 | 83 | 84 | -2 85 | 86 | 87 | 88 | 89 | 2 90 | 91 | 92 | 93 | 94 | 95 | 96 | YES 97 | 98 | YES 99 | -1.CustomClassName 100 | -2.CustomClassName 101 | 2.IBEditorWindowLastContentRect 102 | 2.IBPluginDependency 103 | 104 | 105 | YES 106 | TabThreeController 107 | UIResponder 108 | {{461, 0}, {783, 856}} 109 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 110 | 111 | 112 | 113 | YES 114 | 115 | 116 | YES 117 | 118 | 119 | 120 | 121 | YES 122 | 123 | 124 | YES 125 | 126 | 127 | 128 | 3 129 | 130 | 131 | 132 | YES 133 | 134 | TabThreeController 135 | UIViewController 136 | 137 | IBProjectSource 138 | Classes/TabThreeController.h 139 | 140 | 141 | 142 | UIView 143 | 144 | IBProjectSource 145 | Libraries/NMView/UIView+NMTemplating.h 146 | 147 | 148 | 149 | UIViewController 150 | 151 | IBProjectSource 152 | Libraries/NMViewController/NMNavigationController.h 153 | 154 | 155 | 156 | 157 | YES 158 | 159 | NSObject 160 | 161 | IBFrameworkSource 162 | Foundation.framework/Headers/NSError.h 163 | 164 | 165 | 166 | NSObject 167 | 168 | IBFrameworkSource 169 | Foundation.framework/Headers/NSFileManager.h 170 | 171 | 172 | 173 | NSObject 174 | 175 | IBFrameworkSource 176 | Foundation.framework/Headers/NSKeyValueCoding.h 177 | 178 | 179 | 180 | NSObject 181 | 182 | IBFrameworkSource 183 | Foundation.framework/Headers/NSKeyValueObserving.h 184 | 185 | 186 | 187 | NSObject 188 | 189 | IBFrameworkSource 190 | Foundation.framework/Headers/NSKeyedArchiver.h 191 | 192 | 193 | 194 | NSObject 195 | 196 | IBFrameworkSource 197 | Foundation.framework/Headers/NSObject.h 198 | 199 | 200 | 201 | NSObject 202 | 203 | IBFrameworkSource 204 | Foundation.framework/Headers/NSRunLoop.h 205 | 206 | 207 | 208 | NSObject 209 | 210 | IBFrameworkSource 211 | Foundation.framework/Headers/NSThread.h 212 | 213 | 214 | 215 | NSObject 216 | 217 | IBFrameworkSource 218 | Foundation.framework/Headers/NSURL.h 219 | 220 | 221 | 222 | NSObject 223 | 224 | IBFrameworkSource 225 | Foundation.framework/Headers/NSURLConnection.h 226 | 227 | 228 | 229 | NSObject 230 | 231 | IBFrameworkSource 232 | UIKit.framework/Headers/UIAccessibility.h 233 | 234 | 235 | 236 | NSObject 237 | 238 | IBFrameworkSource 239 | UIKit.framework/Headers/UINibLoading.h 240 | 241 | 242 | 243 | NSObject 244 | 245 | IBFrameworkSource 246 | UIKit.framework/Headers/UIResponder.h 247 | 248 | 249 | 250 | UIResponder 251 | NSObject 252 | 253 | 254 | 255 | UISearchBar 256 | UIView 257 | 258 | IBFrameworkSource 259 | UIKit.framework/Headers/UISearchBar.h 260 | 261 | 262 | 263 | UISearchDisplayController 264 | NSObject 265 | 266 | IBFrameworkSource 267 | UIKit.framework/Headers/UISearchDisplayController.h 268 | 269 | 270 | 271 | UIView 272 | 273 | IBFrameworkSource 274 | UIKit.framework/Headers/UIPrintFormatter.h 275 | 276 | 277 | 278 | UIView 279 | 280 | IBFrameworkSource 281 | UIKit.framework/Headers/UITextField.h 282 | 283 | 284 | 285 | UIView 286 | UIResponder 287 | 288 | IBFrameworkSource 289 | UIKit.framework/Headers/UIView.h 290 | 291 | 292 | 293 | UIViewController 294 | 295 | IBFrameworkSource 296 | UIKit.framework/Headers/UINavigationController.h 297 | 298 | 299 | 300 | UIViewController 301 | 302 | IBFrameworkSource 303 | UIKit.framework/Headers/UIPopoverController.h 304 | 305 | 306 | 307 | UIViewController 308 | 309 | IBFrameworkSource 310 | UIKit.framework/Headers/UISplitViewController.h 311 | 312 | 313 | 314 | UIViewController 315 | 316 | IBFrameworkSource 317 | UIKit.framework/Headers/UITabBarController.h 318 | 319 | 320 | 321 | UIViewController 322 | UIResponder 323 | 324 | IBFrameworkSource 325 | UIKit.framework/Headers/UIViewController.h 326 | 327 | 328 | 329 | 330 | 0 331 | IBIPadFramework 332 | 333 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 334 | 335 | 336 | 337 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 338 | 339 | 340 | YES 341 | ../NMViewController.xcodeproj 342 | 3 343 | 132 344 | 345 | 346 | -------------------------------------------------------------------------------- /Classes/TabTwoController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TabTwoController.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface TabTwoController : UIViewController { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Classes/TabTwoController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TabTwoController.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | #import "TabTwoController.h" 10 | 11 | 12 | @implementation TabTwoController 13 | 14 | 15 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 16 | // Overriden to allow any orientation. 17 | return YES; 18 | } 19 | 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Classes/TabTwoController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1056 5 | 10J4138 6 | 823 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 132 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 | IBIPadFramework 35 | 36 | 37 | IBFirstResponder 38 | IBIPadFramework 39 | 40 | 41 | 42 | 292 43 | 44 | YES 45 | 46 | 47 | 266 48 | {{20, 963}, {728, 21}} 49 | 50 | NO 51 | YES 52 | 7 53 | NO 54 | IBIPadFramework 55 | I'm a label at the bottom. I'll stick to the bottom! 56 | 57 | 1 58 | MCAwIDAAA 59 | 60 | 61 | 3 62 | MQA 63 | 64 | 1 65 | 10 66 | 1 67 | 68 | 69 | 70 | 290 71 | {{20, 20}, {728, 21}} 72 | 73 | NO 74 | YES 75 | 7 76 | NO 77 | IBIPadFramework 78 | I'm on top! 79 | 80 | 81 | 1 82 | 10 83 | 1 84 | 85 | 86 | {768, 1004} 87 | 88 | 89 | 1 90 | MCAwLjYxOTYwNzg0MzEgMC44Nzg0MzEzNzI1AA 91 | 92 | NO 93 | 94 | 2 95 | 96 | IBIPadFramework 97 | 98 | 99 | 100 | 101 | YES 102 | 103 | 104 | view 105 | 106 | 107 | 108 | 3 109 | 110 | 111 | 112 | 113 | YES 114 | 115 | 0 116 | 117 | 118 | 119 | 120 | 121 | -1 122 | 123 | 124 | File's Owner 125 | 126 | 127 | -2 128 | 129 | 130 | 131 | 132 | 2 133 | 134 | 135 | YES 136 | 137 | 138 | 139 | 140 | 141 | 142 | 4 143 | 144 | 145 | 146 | 147 | 5 148 | 149 | 150 | 151 | 152 | 153 | 154 | YES 155 | 156 | YES 157 | -1.CustomClassName 158 | -2.CustomClassName 159 | 2.IBEditorWindowLastContentRect 160 | 2.IBPluginDependency 161 | 4.IBPluginDependency 162 | 5.IBPluginDependency 163 | 164 | 165 | YES 166 | TabTwoController 167 | UIResponder 168 | {{348, 0}, {783, 856}} 169 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 170 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 171 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 172 | 173 | 174 | 175 | YES 176 | 177 | 178 | YES 179 | 180 | 181 | 182 | 183 | YES 184 | 185 | 186 | YES 187 | 188 | 189 | 190 | 5 191 | 192 | 193 | 194 | YES 195 | 196 | TabTwoController 197 | UIViewController 198 | 199 | IBProjectSource 200 | Classes/TabTwoController.h 201 | 202 | 203 | 204 | UIView 205 | 206 | IBProjectSource 207 | Libraries/NMView/UIView+NMTemplating.h 208 | 209 | 210 | 211 | 212 | YES 213 | 214 | NSObject 215 | 216 | IBFrameworkSource 217 | Foundation.framework/Headers/NSError.h 218 | 219 | 220 | 221 | NSObject 222 | 223 | IBFrameworkSource 224 | Foundation.framework/Headers/NSFileManager.h 225 | 226 | 227 | 228 | NSObject 229 | 230 | IBFrameworkSource 231 | Foundation.framework/Headers/NSKeyValueCoding.h 232 | 233 | 234 | 235 | NSObject 236 | 237 | IBFrameworkSource 238 | Foundation.framework/Headers/NSKeyValueObserving.h 239 | 240 | 241 | 242 | NSObject 243 | 244 | IBFrameworkSource 245 | Foundation.framework/Headers/NSKeyedArchiver.h 246 | 247 | 248 | 249 | NSObject 250 | 251 | IBFrameworkSource 252 | Foundation.framework/Headers/NSObject.h 253 | 254 | 255 | 256 | NSObject 257 | 258 | IBFrameworkSource 259 | Foundation.framework/Headers/NSRunLoop.h 260 | 261 | 262 | 263 | NSObject 264 | 265 | IBFrameworkSource 266 | Foundation.framework/Headers/NSThread.h 267 | 268 | 269 | 270 | NSObject 271 | 272 | IBFrameworkSource 273 | Foundation.framework/Headers/NSURL.h 274 | 275 | 276 | 277 | NSObject 278 | 279 | IBFrameworkSource 280 | Foundation.framework/Headers/NSURLConnection.h 281 | 282 | 283 | 284 | NSObject 285 | 286 | IBFrameworkSource 287 | UIKit.framework/Headers/UIAccessibility.h 288 | 289 | 290 | 291 | NSObject 292 | 293 | IBFrameworkSource 294 | UIKit.framework/Headers/UINibLoading.h 295 | 296 | 297 | 298 | NSObject 299 | 300 | IBFrameworkSource 301 | UIKit.framework/Headers/UIResponder.h 302 | 303 | 304 | 305 | UILabel 306 | UIView 307 | 308 | IBFrameworkSource 309 | UIKit.framework/Headers/UILabel.h 310 | 311 | 312 | 313 | UIResponder 314 | NSObject 315 | 316 | 317 | 318 | UISearchBar 319 | UIView 320 | 321 | IBFrameworkSource 322 | UIKit.framework/Headers/UISearchBar.h 323 | 324 | 325 | 326 | UISearchDisplayController 327 | NSObject 328 | 329 | IBFrameworkSource 330 | UIKit.framework/Headers/UISearchDisplayController.h 331 | 332 | 333 | 334 | UIView 335 | 336 | IBFrameworkSource 337 | UIKit.framework/Headers/UIPrintFormatter.h 338 | 339 | 340 | 341 | UIView 342 | 343 | IBFrameworkSource 344 | UIKit.framework/Headers/UITextField.h 345 | 346 | 347 | 348 | UIView 349 | UIResponder 350 | 351 | IBFrameworkSource 352 | UIKit.framework/Headers/UIView.h 353 | 354 | 355 | 356 | UIViewController 357 | 358 | IBFrameworkSource 359 | UIKit.framework/Headers/UINavigationController.h 360 | 361 | 362 | 363 | UIViewController 364 | 365 | IBFrameworkSource 366 | UIKit.framework/Headers/UIPopoverController.h 367 | 368 | 369 | 370 | UIViewController 371 | 372 | IBFrameworkSource 373 | UIKit.framework/Headers/UISplitViewController.h 374 | 375 | 376 | 377 | UIViewController 378 | 379 | IBFrameworkSource 380 | UIKit.framework/Headers/UITabBarController.h 381 | 382 | 383 | 384 | UIViewController 385 | UIResponder 386 | 387 | IBFrameworkSource 388 | UIKit.framework/Headers/UIViewController.h 389 | 390 | 391 | 392 | 393 | 0 394 | IBIPadFramework 395 | 396 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 397 | 398 | 399 | 400 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 401 | 402 | 403 | YES 404 | ../NMViewController.xcodeproj 405 | 3 406 | 132 407 | 408 | 409 | -------------------------------------------------------------------------------- /Libraries/NMView/NMView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMView.h 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 17.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | 41 | /** 42 | * The NMView class allows the creation of custom UIView subclasses using nib 43 | * files to specify the layout of the view. 44 | * 45 | * Typically, when creating UIView subclasses, the view's appearance and its 46 | * subview hierarchy have to be assembled in code. This can become tedious and 47 | * is prone to error. With NMView, you design your view's layout using IB, save 48 | * the layout in a nib file and load the view with its layout during its 49 | * initialization. 50 | * 51 | * 1. View layouts using nib files 52 | * 53 | * NMView provides a default implementation of the -loadViewWithNibName:bundle: 54 | * method which is used to load the view's layout from a nib file. The 55 | * implementation relies on a special structure of the nib file which is 56 | * described in detail in the documentation of -loadViewWithNibName:bundle:. 57 | * 58 | * For initialization of your view in code, you can either use the regular 59 | * -initWithFrame: method or the -initWithNibName:bundle: method. If the view is 60 | * initialized as part of a nib loading process (eg. when the view is added as 61 | * a subview to a UIViewController's view hierarchy in the view controller's nib 62 | * file), the -initWithCoder: method is used to initialize the view. 63 | * 64 | * Each of the initialization methods try to load the view's layout from a nib 65 | * file using -loadViewWithNibName:bundle:. The -initWithFrame: and 66 | * -initWithCoder: methods try to load the nib by passing nil for the nib name 67 | * and nil for the bundle, the -initWithNibName:bundle: method passes its 68 | * argument values to -loadViewWithNibName:bundle:. Passing nil / nil will try 69 | * to load a nib with the class name's name from the main bundle. 70 | * 71 | * If NMView cannot load the view from a nib (either because there is no 72 | * matching nib file or because the nib's structure does not fit the loading 73 | * process), it will call the -createView method as a last resort for creating 74 | * the view's layout programmatically. Therefore, even when creating your view's 75 | * layout in code, subclassing from NMView can make sense since -createView is 76 | * called regardless of the initializer used to create the instance. 77 | * 78 | * After the view has been loaded (either from a nib or using -createView), the 79 | * -viewDidLoad method is called. You can override the method in your custom 80 | * NMView subclass to perform some post-processing work that cannot be performed 81 | * in Interface Builder. 82 | * 83 | * One obvious thing to point out: since NMView (and its subclasses) directly 84 | * inherits from UIView, its view is loaded during initialization for whole 85 | * lifetime of an instance of the class. This is in contrast to a 86 | * UIViewController where the controller can exist without the associated view 87 | * (ie. -initWithNibName:bundle: on UIViewController does *not* load the view). 88 | * Therefore, for NMView, -viewDidLoad is always called exactly once during the 89 | * lifetime of an NMView instance whereas a UIViewController's -viewDidLoad 90 | * might be called multiple times. 91 | * 92 | * 2. Alternative layouts 93 | * 94 | * On top of loading the view's layout from a nib file, NMView also supports 95 | * alternative layouts that can be activated based on the current bounds of the 96 | * view. This allows, for example, for the creation of different layouts of the 97 | * same NMView subclass for portrait and landscape orientations that cannot be 98 | * implemented using regular view autoresizing. 99 | * 100 | * Layouts can either be activated manually using the -changeLayoutIfNecessary 101 | * method or can be changed automatically by setting the 102 | * automaticLayoutChangeEnabled property to YES. In that case, each call to 103 | * -layoutSubviews automatically calls -changeLayoutIfNecessary. 104 | * 105 | * Once a layout has been applied, the -layoutDidChangeToAspectRatio: method is 106 | * called to allow the NMView subclass to perform some post-processing on the 107 | * new layout. In this method you can, for example, apply modifications to your 108 | * layout that you cannot define in IB (like change the transform of one of the 109 | * subviews). 110 | * 111 | * For NMView to be able to load alternative layouts, the layouts have to be 112 | * specified in the same nib that the view is loaded from. Next to the regular 113 | * view layout, the nib will have to include another top-level view of the exact 114 | * same hierarchy for each alternative layout. Using Interface Builder, the 115 | * subviews in the alternative layout can now be re-arranged (as long as their 116 | * hierarchy is kept in the same shape as the regular layout). Once done, the 117 | * top-level view's type of each alternative layout has to be changed to 118 | * NMViewLayoutView so that NMView can detect which of the views should be used 119 | * for alternative layouts and which views might serve a different purpose (like 120 | * being injected into IBOutlets of your view). 121 | */ 122 | @interface NMView : UIView { 123 | 124 | @private 125 | 126 | NSMutableArray *layouts; 127 | BOOL automaticLayoutChangeEnabled; 128 | 129 | } 130 | 131 | 132 | #pragma mark View Loading 133 | 134 | /** 135 | * Initializes a new view object by first calling -initWithFrame: of UIView with 136 | * a default CGRect and subsequently trying to load the view by calling 137 | * -loadViewWithNibName:bundle: passing nil / nil for the nib name and bundle. 138 | * 139 | * If the a nib file was loaded successfully, the view's frame will be set to 140 | * that loaded from the nib file. If no matching nib was found, the -createView 141 | * method can reset the default frame to a more suitable value. 142 | */ 143 | - (id)init; 144 | 145 | /** 146 | * Initializes a new view object by first calling -initWithFrame: of UIView and 147 | * subsequently trying to load the view by calling -loadViewWithNibName:bundle: 148 | * passing nil / nil for the nib name and bundle. 149 | * 150 | * After the view has been loaded from the nib, the view's frame is reset to the 151 | * parameter passed into the method, overriding the frame that was set in the 152 | * view's nib. 153 | */ 154 | - (id)initWithFrame:(CGRect)frame; 155 | 156 | /** 157 | * Initializes a new view object from the given nib file. 158 | * 159 | * This method calls -loadViewWithNibName:bundle: to perform the actual view 160 | * loading. 161 | */ 162 | - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle; 163 | 164 | /** 165 | * Loads the View's properties from the given nib file. 166 | * 167 | * If nibBundle is nil, [NSBundle mainBundle] is used for loading the nib. 168 | * If nibName is nil, we're trying to load a nib with the name of the current 169 | * class. 170 | * If the nib was loaded properly, it has to contain at least one object of 171 | * type UIView. That UIView object's properties are applied to this view to 172 | * customize its appearance and view hierarchy. The nib is searched for the 173 | * UIView "from top to bottom" (ie. the first UIView object contained in the nib 174 | * is used. 175 | * If no nib could be found, the -createView method is called as a last resort 176 | * to construct the view programatically. 177 | * 178 | * Override this method to provide your own loading strategy. This method should 179 | * not be called by users of NMView and is only meant for subclassing. 180 | */ 181 | - (void)loadViewWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle; 182 | 183 | /** 184 | * Programmatically creates the view and its hierarchy. 185 | * 186 | * Override this method to create your custom view subclass. This method should 187 | * not be called by users of NMView and is only meant for subclassing. 188 | * 189 | * The default implementation does nothing. 190 | */ 191 | - (void)createView; 192 | 193 | /** 194 | * Called after the view was loaded either from a nib or using the -createView 195 | * method. 196 | * 197 | * Override this method to perform any view customization when loading did 198 | * finish. This method should not be called by users of NMView and is only meant 199 | * for subclassing. 200 | * 201 | * The default implementation does nothing. 202 | */ 203 | - (void)viewDidLoad; 204 | 205 | 206 | #pragma mark Layout Management 207 | 208 | #define AspectRatioIsHorizontal(aspectRatio) ((aspectRatio) > 1) 209 | #define AspectRatioIsVertical(aspectRatio) ((aspectRatio) < 1) 210 | #define AspectRatioIsSquare(aspectRatio) ((aspectRatio) == 1) 211 | 212 | /** 213 | * Enables automatic layout changes whenever -layoutSubviews is called. The 214 | * default value is NO. 215 | */ 216 | @property (nonatomic, assign) BOOL automaticLayoutChangeEnabled; 217 | 218 | /** 219 | * Called to ask the view to update its layout based on the aspect ratio of the 220 | * view's bounds. If the current layout is the best layout available given the 221 | * current aspect ratio, no change is performed but 222 | * -layoutDidChangeToAspectRatio: will still be invoked. 223 | */ 224 | - (void)changeLayoutIfNecessary; 225 | 226 | /** 227 | * Called after the layout of a view was changed during a call to 228 | * -changeLayoutIfNecessary to better match the current aspect ratio. 229 | * 230 | * Override this method to dynamically adapt to the layout change. This method 231 | * should not be called by users of NMView and is only meant for subclassing. 232 | */ 233 | - (void)layoutDidChangeToAspectRatio:(CGFloat)aspectRatio; 234 | 235 | @end 236 | -------------------------------------------------------------------------------- /Libraries/NMView/NMView.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMView.m 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 17.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMView.h" 39 | 40 | #import "NMViewLayout.h" 41 | #import "NMViewLayoutView.h" 42 | #import "UIView+NMTemplating.h" 43 | 44 | 45 | @implementation NMView 46 | 47 | #pragma mark Properties 48 | 49 | @synthesize automaticLayoutChangeEnabled; 50 | 51 | 52 | #pragma mark Methods to be overridden by subclasses 53 | 54 | - (void)loadViewWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle { 55 | // 0. Initialize 56 | layouts = [[NSMutableArray alloc] init]; 57 | 58 | // 1. check for nil values and use default values, if necessary 59 | if (nibName == nil) nibName = NSStringFromClass([self class]); 60 | if (bundle == nil) bundle = [NSBundle mainBundle]; 61 | 62 | // 2. test if nib exists in bundle 63 | BOOL viewLoadedFromNib = NO; 64 | NSString *path = [bundle pathForResource:nibName ofType:@"nib"]; 65 | if (path != nil) { 66 | // 2a. try to load from nib 67 | NSArray *nibContent = [bundle loadNibNamed:nibName owner:self options:nil]; 68 | if (nibContent != nil) { 69 | for (NSUInteger i = 0; i < [nibContent count]; i++) { 70 | NSObject *object = [nibContent objectAtIndex:i]; 71 | 72 | if ([object isKindOfClass:[UIView class]]) { 73 | UIView *view = (UIView *)object; 74 | 75 | if (!viewLoadedFromNib) { 76 | // apply nib template to current view 77 | [self applyViewTemplateByCopyingHierarchy:view]; 78 | [layouts addObject:[NMViewLayout layoutForView:self 79 | withAlternativeView:self]]; 80 | 81 | viewLoadedFromNib = YES; 82 | } else if (view.tag == NMViewLayoutTag 83 | || [view isKindOfClass:[NMViewLayoutView class]]) { 84 | [layouts addObject:[NMViewLayout layoutForView:self 85 | withAlternativeView:view]]; 86 | } 87 | } 88 | } 89 | } 90 | } 91 | 92 | // 3. create view using code if nib loading failed 93 | if (!viewLoadedFromNib) { 94 | [self createView]; 95 | } 96 | 97 | // 4. let subclasses know that the view did load 98 | [self viewDidLoad]; 99 | } 100 | 101 | - (void)createView { } 102 | 103 | - (void)viewDidLoad { } 104 | 105 | 106 | #pragma mark Layout Management 107 | 108 | - (void)layoutSubviews { 109 | if (self.automaticLayoutChangeEnabled) { 110 | [self changeLayoutIfNecessary]; 111 | } 112 | } 113 | 114 | - (void)changeLayoutIfNecessary { 115 | CGFloat aspectRatio = self.bounds.size.width/self.bounds.size.height; 116 | CGFloat smallestDifference = 100; 117 | NMViewLayout *closestLayout = nil; 118 | 119 | for (NMViewLayout *layout in layouts) { 120 | if (ABS(layout.aspectRatio-aspectRatio) < smallestDifference) { 121 | smallestDifference = ABS(layout.aspectRatio-aspectRatio); 122 | closestLayout = layout; 123 | } 124 | } 125 | 126 | 127 | if (closestLayout != nil) { 128 | [closestLayout applyToView:self]; 129 | [self layoutDidChangeToAspectRatio:closestLayout.aspectRatio]; 130 | } 131 | } 132 | 133 | - (void)layoutDidChangeToAspectRatio:(CGFloat)aspectRatio { } 134 | 135 | 136 | #pragma mark Init 137 | 138 | - (id)init { 139 | return [self initWithNibName:nil bundle:nil]; 140 | } 141 | 142 | - (id)initWithNibName:(NSString*)name bundle:(NSBundle*)bundle { 143 | // use a dummy rect to initialize the UIView object 144 | if ((self = [super initWithFrame:CGRectMake(0, 0, 100, 100)])) { 145 | // load the view's layout, maintaining the rect that was set in the nib 146 | [self loadViewWithNibName:name bundle:bundle]; 147 | 148 | // re-layout (in case of a view which changes layouts automatically) 149 | [self layoutSubviews]; 150 | } 151 | return self; 152 | } 153 | 154 | - (id)initWithFrame:(CGRect)frame { 155 | if ((self = [super initWithFrame:frame])) { 156 | // load the view's layout 157 | [self loadViewWithNibName:nil bundle:nil]; 158 | 159 | // overwrite the nib-loaded frame with the given frame parameter 160 | self.frame = frame; 161 | 162 | // re-layout (in case of a view which changes layouts automatically) 163 | [self layoutSubviews]; 164 | } 165 | return self; 166 | } 167 | 168 | - (id)initWithCoder:(NSCoder *)aDecoder { 169 | if ((self = [super initWithCoder:aDecoder])) { 170 | // store the frame and tag loaded from the nib which is using this view 171 | CGRect frameBeforeLoad = self.frame; 172 | NSInteger t = self.tag; 173 | 174 | // load the view's layout 175 | [self loadViewWithNibName:nil bundle:nil]; 176 | 177 | // overwrite the nib-loaded frame and tag with the frame and tag of the 178 | // nib using this view 179 | self.frame = frameBeforeLoad; 180 | self.tag = t; 181 | 182 | // re-layout (in case of a view which changes layouts automatically) 183 | [self layoutSubviews]; 184 | } 185 | return self; 186 | } 187 | 188 | - (void)dealloc { 189 | [layouts release]; 190 | 191 | [super dealloc]; 192 | } 193 | 194 | @end 195 | -------------------------------------------------------------------------------- /Libraries/NMView/NMViewLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewLayout.h 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 18.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | 41 | #define NMViewLayoutTag 66768 42 | #define NMViewLayoutOmitSubviewsTag 66769 43 | 44 | 45 | @interface NMViewLayout : NSObject { 46 | 47 | CGRect alternativeBaseFrame; 48 | UIView *baseView; 49 | NSMutableDictionary *configuration; 50 | 51 | } 52 | 53 | @property (nonatomic, readonly) CGFloat aspectRatio; 54 | @property (nonatomic, readonly) CGRect alternativeBaseFrame; 55 | 56 | + (NMViewLayout *)layoutForView:(UIView *)original 57 | withAlternativeView:(UIView *)alternative; 58 | 59 | - (void)applyToView:(UIView *)view; 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Libraries/NMView/NMViewLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewLayout.m 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 18.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMViewLayout.h" 39 | 40 | #import "NMViewLayoutOmitSubviewsView.h" 41 | #import "NMViewLayoutView.h" 42 | 43 | 44 | #pragma mark - 45 | #pragma mark NMViewLayoutConfiguration Implementation 46 | 47 | @interface NMViewLayoutConfiguration : NSObject { 48 | CGRect frame; 49 | CGFloat alpha; 50 | UIViewAutoresizing autoresizingMask; 51 | } 52 | 53 | @property (nonatomic, assign) CGRect frame; 54 | @property (nonatomic, assign) CGFloat alpha; 55 | @property (nonatomic, assign) UIViewAutoresizing autoresizingMask; 56 | 57 | + (NMViewLayoutConfiguration *)configurationWithFrame:(CGRect)f 58 | alpha:(CGFloat)a 59 | autoresizingMask:(UIViewAutoresizing)mask; 60 | 61 | @end 62 | 63 | @implementation NMViewLayoutConfiguration 64 | 65 | @synthesize frame, alpha, autoresizingMask; 66 | 67 | + (NMViewLayoutConfiguration *)configurationWithFrame:(CGRect)f 68 | alpha:(CGFloat)a 69 | autoresizingMask:(UIViewAutoresizing)mask { 70 | NMViewLayoutConfiguration *config = [[[NMViewLayoutConfiguration alloc] init] autorelease]; 71 | config.frame = f; 72 | config.alpha = a; 73 | config.autoresizingMask = mask; 74 | return config; 75 | } 76 | 77 | @end 78 | 79 | 80 | #pragma mark - 81 | #pragma mark NMViewLayout Implementation 82 | 83 | @implementation NMViewLayout 84 | 85 | @synthesize alternativeBaseFrame; 86 | 87 | - (CGFloat)aspectRatio { 88 | return alternativeBaseFrame.size.width/alternativeBaseFrame.size.height; 89 | } 90 | 91 | 92 | - (void)addConfiguration:(id)config forView:(UIView *)view { 93 | NSNumber *num = [NSNumber numberWithUnsignedInteger:(NSUInteger)view]; 94 | [configuration setObject:config forKey:num]; 95 | } 96 | 97 | - (id)configurationForView:(UIView *)view { 98 | return [configuration objectForKey:[NSNumber numberWithUnsignedInteger:(NSUInteger)view]]; 99 | } 100 | 101 | 102 | - (BOOL)shouldUseSubviewsForView:(UIView *)view { 103 | NSString *classname = NSStringFromClass([view class]); 104 | 105 | return (view.tag != NMViewLayoutOmitSubviewsTag 106 | && ![view isKindOfClass:[NMViewLayoutOmitSubviewsView class]] 107 | && (view == baseView 108 | || [classname isEqualToString:NSStringFromClass([NMViewLayoutView class])] 109 | || [classname isEqualToString:@"UIView"] 110 | || [classname isEqualToString:@"UIScrollView"])); 111 | } 112 | 113 | 114 | - (void)applyToView:(UIView *)view { 115 | if (view != baseView) { 116 | NMViewLayoutConfiguration *config = [self configurationForView:view]; 117 | view.frame = config.frame; 118 | //view.alpha = config.alpha; 119 | //view.autoresizingMask = config.autoresizingMask; 120 | } 121 | 122 | if ([self shouldUseSubviewsForView:view]) { 123 | for (NSUInteger i = 0; i < [view.subviews count]; i++) { 124 | [self applyToView:[view.subviews objectAtIndex:i]]; 125 | } 126 | } 127 | } 128 | 129 | 130 | - (void)addLayoutForView:(UIView *)original 131 | alternativeView:(UIView *)alternative { 132 | 133 | NMViewLayoutConfiguration *config = [NMViewLayoutConfiguration configurationWithFrame:alternative.frame 134 | alpha:alternative.alpha 135 | autoresizingMask:alternative.autoresizingMask]; 136 | 137 | [self addConfiguration:config forView:original]; 138 | 139 | if ([self shouldUseSubviewsForView:alternative]) { 140 | for (NSUInteger i = 0; i < [original.subviews count]; i++) { 141 | UIView *subview = [original.subviews objectAtIndex:i]; 142 | 143 | if (i < [alternative.subviews count]) { 144 | UIView *alternativeSubview = [alternative.subviews objectAtIndex:i]; 145 | 146 | [self addLayoutForView:subview alternativeView:alternativeSubview]; 147 | } 148 | } 149 | } 150 | } 151 | 152 | 153 | + (NMViewLayout *)layoutForView:(UIView *)original 154 | withAlternativeView:(UIView *)alternative { 155 | 156 | NMViewLayout *layout = [[[NMViewLayout alloc] init] autorelease]; 157 | layout->alternativeBaseFrame = alternative.frame; 158 | layout->baseView = original; 159 | 160 | [layout addLayoutForView:original alternativeView:alternative]; 161 | 162 | return layout; 163 | } 164 | 165 | - (id)init { 166 | if ((self = [super init])) { 167 | configuration = [[NSMutableDictionary alloc] init]; 168 | } 169 | 170 | return self; 171 | } 172 | 173 | - (void)dealloc { 174 | [configuration release]; 175 | 176 | [super dealloc]; 177 | } 178 | 179 | @end 180 | -------------------------------------------------------------------------------- /Libraries/NMView/NMViewLayoutOmitSubviewsView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewLayoutOmitSubviewsView.h 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 21.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | 41 | /** 42 | * A class which serves only as a marker in Interface Builder to identify the 43 | * views for which the layout should omit subviews and not re-layout their 44 | * subviews. 45 | */ 46 | @interface NMViewLayoutOmitSubviewsView : UIView { 47 | 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Libraries/NMView/NMViewLayoutOmitSubviewsView.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewLayoutOmitSubviewsView.m 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 21.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMViewLayoutOmitSubviewsView.h" 39 | 40 | 41 | @implementation NMViewLayoutOmitSubviewsView 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Libraries/NMView/NMViewLayoutView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewLayoutView.h 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 21.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | 41 | /** 42 | * A class which serves only as a marker in Interface Builder to identify the 43 | * views which should be used as layouts for the NMView. 44 | */ 45 | @interface NMViewLayoutView : UIView { 46 | 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Libraries/NMView/NMViewLayoutView.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewLayoutView.m 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 21.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMViewLayoutView.h" 39 | 40 | 41 | @implementation NMViewLayoutView 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Libraries/NMView/UIImage+NMNSCoding.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+NMNSCoding.h 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 17.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | 41 | @interface UIImage (NMNSCoding) 42 | 43 | - (id)initWithCoder:(NSCoder *)decoder; 44 | - (void)encodeWithCoder:(NSCoder *)encoder; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Libraries/NMView/UIImage+NMNSCoding.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+NMNSCoding.m 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 17.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "UIImage+NMNSCoding.h" 39 | 40 | #define kEncodingKey @"imageData" 41 | 42 | 43 | @implementation UIImage (NMNSCoding) 44 | 45 | - (id)initWithCoder:(NSCoder *)decoder 46 | { 47 | if ((self = [super init])) 48 | { 49 | NSData *data = [decoder decodeObjectForKey:kEncodingKey]; 50 | self = [self initWithData:data]; 51 | } 52 | 53 | return self; 54 | } 55 | - (void)encodeWithCoder:(NSCoder *)encoder 56 | { 57 | NSData *data = UIImagePNGRepresentation(self); 58 | [encoder encodeObject:data forKey:kEncodingKey]; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Libraries/NMView/UIView+NMTemplating.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+NMTemplating.h 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 17.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | #import 40 | 41 | 42 | @interface UIView (NMTemplating) 43 | 44 | - (void)applyViewTemplate:(UIView *)view; 45 | 46 | - (void)applyViewTemplateByCopyingHierarchy:(UIView *)view; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Libraries/NMView/UIView+NMTemplating.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+NMTemplating.m 3 | // NMView 4 | // 5 | // Created by Benjamin Broll on 17.02.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "UIView+NMTemplating.h" 39 | 40 | 41 | @implementation UIView (NMTemplating) 42 | 43 | 44 | - (void)applyViewProperties:(UIView *)view { 45 | // Visual Appearance 46 | self.backgroundColor = view.backgroundColor; 47 | self.hidden = view.hidden; 48 | self.alpha = view.alpha; 49 | self.opaque = view.opaque; 50 | self.clipsToBounds = view.clipsToBounds; 51 | self.clearsContextBeforeDrawing = view.clearsContextBeforeDrawing; 52 | 53 | // Event-Related 54 | self.userInteractionEnabled = view.userInteractionEnabled; 55 | self.multipleTouchEnabled = view.multipleTouchEnabled; 56 | self.exclusiveTouch = view.exclusiveTouch; 57 | 58 | // Resizing Behaviour 59 | self.autoresizingMask = view.autoresizingMask; 60 | self.autoresizesSubviews = view.autoresizesSubviews; 61 | self.contentMode = view.contentMode; 62 | self.contentStretch = view.contentStretch; 63 | 64 | // Drawing / Updating 65 | if ([self respondsToSelector:@selector(contentScaleFactor)]) { 66 | self.contentScaleFactor = view.contentScaleFactor; 67 | } 68 | 69 | // Identifying 70 | self.tag = view.tag; 71 | 72 | // Bounds 73 | self.bounds = view.bounds; 74 | } 75 | 76 | 77 | - (UIView *)copyView { 78 | if ([self respondsToSelector:@selector(encodeWithCoder:)]) { 79 | NSMutableData *data = [[NSMutableData alloc] init]; 80 | 81 | NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; 82 | [archiver encodeObject:self forKey:@"view"]; 83 | [archiver finishEncoding]; 84 | [archiver release]; 85 | 86 | NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; 87 | UIView *copy = [unarchiver decodeObjectForKey:@"view"]; 88 | [unarchiver finishDecoding]; 89 | [unarchiver release]; 90 | 91 | [data release]; 92 | 93 | return copy; 94 | } else { 95 | return nil; 96 | } 97 | } 98 | 99 | 100 | - (void)applyViewTemplate:(UIView *)view { 101 | // Apply Properties 102 | [self applyViewProperties:view]; 103 | 104 | // Re-Create subview structure 105 | for (UIView *subview in view.subviews) { 106 | UIView *copy = [subview copyView]; 107 | [self addSubview:copy]; 108 | } 109 | } 110 | 111 | - (void)applyViewTemplateByCopyingHierarchy:(UIView *)view { 112 | // Apply Properties 113 | [self applyViewProperties:view]; 114 | 115 | // Detach / Attach subviews 116 | for (UIView *subview in view.subviews) { 117 | [subview retain]; 118 | [subview removeFromSuperview]; 119 | 120 | [self addSubview:subview]; 121 | 122 | [subview release]; 123 | } 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMNavigationBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMNavigationBar.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 30.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | #import "NMView.h" 41 | 42 | 43 | @protocol NMNavigationBarDelegate; 44 | 45 | 46 | 47 | @interface NMNavigationBar : NMView { 48 | 49 | // State 50 | id delegate; 51 | 52 | } 53 | 54 | @property (nonatomic, assign) id delegate; 55 | 56 | - (void)setNavigationStack:(NSArray *)viewControllers animated:(BOOL)isAnimated; 57 | 58 | @end 59 | 60 | 61 | @protocol NMNavigationBarDelegate 62 | 63 | - (void)navigationBarDidPop:(NMNavigationBar *)bar; 64 | 65 | @end -------------------------------------------------------------------------------- /Libraries/NMViewController/NMNavigationBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMNavigationBar.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 30.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMNavigationBar.h" 39 | 40 | 41 | @implementation NMNavigationBar 42 | 43 | #pragma mark Properties 44 | 45 | @synthesize delegate; 46 | 47 | 48 | #pragma mark Public API 49 | 50 | - (void)setNavigationStack:(NSArray *)viewControllers animated:(BOOL)isAnimated { 51 | // override in subclass 52 | } 53 | 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMNavigationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMNavigationController.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 10.11.10. 6 | // Copyright 2010 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | #import "NMNavigationBar.h" 41 | #import "NMViewController.h" 42 | 43 | 44 | @protocol NMNavigationControllerDelegate; 45 | 46 | 47 | @interface NMNavigationController : NMViewController { 48 | 49 | // View 50 | UIView *contentContainerView; 51 | UIView *navigationBarContainerView; 52 | 53 | // State 54 | id delegate; 55 | NSMutableArray *viewControllers; 56 | // - the navigation bar view 57 | NMNavigationBar *navigationBar; 58 | 59 | } 60 | 61 | @property (nonatomic, retain) IBOutlet UIView *contentContainerView; 62 | @property (nonatomic, retain) IBOutlet UIView *navigationBarContainerView; 63 | 64 | @property (nonatomic, assign) id delegate; 65 | @property (nonatomic, copy) NSArray *viewControllers; 66 | @property (nonatomic, retain) UIViewController *topViewController; 67 | // currently, the tab has to be able to fill the whole width of the screen 68 | // the tab bar's height is used as is 69 | @property (nonatomic, retain) NMNavigationBar *navigationBar; 70 | 71 | - (void)setViewControllers:(NSArray *)vcs animated:(BOOL)isAnimated; 72 | 73 | - (void)pushViewController:(UIViewController *)vc animated:(BOOL)isAnimated; 74 | - (UIViewController *)popViewControllerAnimated:(BOOL)isAnimated; 75 | - (NSArray *)popToViewController:(UIViewController *)vc animated:(BOOL)isAnimated; 76 | - (NSArray *)popToRootViewControllerAnimated:(BOOL)isAnimated; 77 | 78 | @end 79 | 80 | 81 | @protocol NMNavigationControllerDelegate 82 | 83 | @optional 84 | 85 | - (void) navigationController:(NMNavigationController *)navigationVC didPushViewController:(UIViewController *)vc; 86 | - (void) navigationController:(NMNavigationController *)navigationVC didPopViewController:(UIViewController *)vc; 87 | 88 | @end 89 | 90 | 91 | @interface UIViewController (NMNavigationControllerAdditions) 92 | 93 | @property (nonatomic, retain) NMNavigationController *nmNavigationController; 94 | 95 | @end 96 | 97 | 98 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMNavigationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMNavigationController.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 10.11.10. 6 | // Copyright 2010 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMNavigationController.h" 39 | 40 | #import 41 | 42 | #import "NMViewController.h" 43 | 44 | 45 | #define UIKIT_FORWARDS_APPEARANCE() [UIViewController instancesRespondToSelector:@selector(automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers)] 46 | 47 | #define ANIMATIONDURATION 0.3 // in seconds 48 | 49 | 50 | typedef enum { 51 | NMNavigationControllerPositionCurrent, 52 | NMNavigationControllerPositionBack, 53 | NMNavigationControllerPositionNext 54 | } NMNavigationControllerPosition; 55 | 56 | typedef enum { 57 | NMNavigationControllerTransitionNone, 58 | NMNavigationControllerTransitionPush, 59 | NMNavigationControllerTransitionPop 60 | } NMNavigationControllerTransition; 61 | 62 | 63 | @interface NMNavigationController (Private) 64 | 65 | - (void)transition:(NMNavigationControllerTransition)transition 66 | toViewController:(UIViewController *)destinationController animated:(BOOL)isAnimated; 67 | 68 | - (void)addViewControllers:(NSArray *)vcs; 69 | - (void)removeAllViewControllers; 70 | - (void)removeViewControllersUpToViewController:(UIViewController *)vc; 71 | - (void)removeViewController:(UIViewController *)vc; 72 | - (void)applyPostion:(NMNavigationControllerPosition)position toViewController:(UIViewController *)vc; 73 | 74 | - (void)addNavigationBarAsSubview; 75 | 76 | - (NSComparisonResult)compareSystemVersionWithVersion:(NSString *)version; 77 | 78 | @end 79 | 80 | 81 | 82 | @implementation NMNavigationController 83 | 84 | #pragma mark Properties 85 | 86 | @synthesize contentContainerView, navigationBarContainerView; 87 | @synthesize delegate, viewControllers, navigationBar; 88 | 89 | - (void)setViewControllers:(NSArray *)vcs { 90 | [self setViewControllers:vcs animated:NO]; 91 | } 92 | 93 | - (void) setViewControllers:(NSArray *)vcs animated:(BOOL)isAnimated { 94 | // prevent a stack that contains duplicates 95 | NSSet *vcsWithoutDuplicates = [NSSet setWithArray:vcs]; 96 | if ([vcsWithoutDuplicates count] < [vcs count]) { 97 | [NSException raise:@"NSInvalidArgumentException" 98 | format:@"Setting a view controller stack including the same controller multiple times is not supported (%@)", vcs]; 99 | } 100 | 101 | // prevent an empty stack 102 | if ([vcs count] == 0) { 103 | [NSException raise:@"NSInvalidArgumentException" 104 | format:@"Setting an empty view controller stack is not supported (%@)", vcs]; 105 | } 106 | 107 | // update the navigation bar 108 | [navigationBar setNavigationStack:vcs animated:isAnimated]; 109 | 110 | if ([self isViewLoaded] && self.view.superview != nil) { 111 | if ([viewControllers count] == 0) { 112 | // we cannot animate a transition from an empty stack 113 | // --> just make the top controller visible 114 | [self addViewControllers:vcs]; 115 | 116 | [navigationBar setNavigationStack:viewControllers animated:NO]; 117 | 118 | UIViewController *destinationController = [vcs lastObject]; 119 | 120 | [self applyPostion:NMNavigationControllerPositionCurrent toViewController:destinationController]; 121 | destinationController.view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); 122 | [self.contentContainerView addSubview:destinationController.view]; 123 | if (!UIKIT_FORWARDS_APPEARANCE()) [destinationController viewWillAppear:NO]; 124 | if (!UIKIT_FORWARDS_APPEARANCE()) [destinationController viewDidAppear:NO]; 125 | } else { 126 | // animated transition from a non-empty stack to a non-empty stack 127 | // --> determine transition information and animate if necessary 128 | 129 | // determine how we transition to the new topViewController 130 | NMNavigationControllerTransition transition; 131 | if (![viewControllers containsObject:[vcs lastObject]]) { 132 | transition = NMNavigationControllerTransitionPush; 133 | } else if ([viewControllers lastObject] == [vcs lastObject]) { 134 | transition = NMNavigationControllerTransitionNone; 135 | } else { 136 | transition = NMNavigationControllerTransitionPop; 137 | } 138 | 139 | // replace previous stack by new stack but keep topViewController for a 140 | // (potentially) necessary transition 141 | [self removeViewControllersUpToViewController:[viewControllers lastObject]]; 142 | for (NSUInteger controllerIndex = 0; controllerIndex < [vcs count]; controllerIndex++) { 143 | UIViewController *vc = [vcs objectAtIndex:controllerIndex]; 144 | vc.nmNavigationController = self; 145 | [viewControllers insertObject:vc atIndex:controllerIndex]; 146 | } 147 | 148 | // perform the requested transition 149 | if (transition == NMNavigationControllerTransitionNone) { 150 | // both arrays contained the same last object so that it's now present 151 | // twice - remove one of the duplicates 152 | [viewControllers removeLastObject]; 153 | } else { 154 | UIViewController *destinationController = [viewControllers objectAtIndex:[viewControllers count]-2]; 155 | [self transition:transition toViewController:destinationController animated:isAnimated]; 156 | } 157 | } 158 | } else { 159 | // we're not visible yet 160 | // --> just remember our controllers, they will be made visible later 161 | [self removeAllViewControllers]; 162 | [self addViewControllers:vcs]; 163 | } 164 | } 165 | 166 | - (void) setTopViewController:(UIViewController *)vc { 167 | NSMutableArray *newControllerStack = [NSMutableArray arrayWithArray:viewControllers]; 168 | [newControllerStack removeLastObject]; 169 | 170 | if ([newControllerStack containsObject:vc]) { 171 | [NSException raise:@"NSInvalidArgumentException" 172 | format:@"Pushing the same view controller instance more than once is not supported (%@)", vc]; 173 | } 174 | 175 | [newControllerStack addObject:vc]; 176 | [self setViewControllers:newControllerStack animated:NO]; 177 | } 178 | 179 | - (UIViewController*)topViewController { 180 | return [viewControllers lastObject]; 181 | } 182 | 183 | - (void)setNavigationBar:(NMNavigationBar *)nb { 184 | if (navigationBar != nb) { 185 | navigationBar.delegate = nil; 186 | if (navigationBar.superview != nil) [navigationBar removeFromSuperview]; 187 | [navigationBar release]; 188 | 189 | navigationBar = [nb retain]; 190 | navigationBar.delegate = self; 191 | } 192 | 193 | if ([self isViewLoaded]) [self addNavigationBarAsSubview]; 194 | } 195 | 196 | 197 | #pragma mark Pushing / Popping 198 | 199 | - (void)pushViewController:(UIViewController *)vc animated:(BOOL)isAnimated { 200 | if ([viewControllers containsObject:vc]) { 201 | [NSException raise:@"NSInvalidArgumentException" 202 | format:@"Pushing the same view controller instance more than once is not supported (%@)", vc]; 203 | } 204 | 205 | NSMutableArray *newStack = [NSMutableArray arrayWithArray:viewControllers]; 206 | [newStack addObject:vc]; 207 | [self setViewControllers:newStack animated:isAnimated]; 208 | } 209 | 210 | - (UIViewController *)popViewControllerAnimated:(BOOL)isAnimated { 211 | if ([viewControllers count] > 1) { 212 | NSMutableArray *newStack = [NSMutableArray arrayWithArray:viewControllers]; 213 | UIViewController *removed = [newStack lastObject]; 214 | [newStack removeLastObject]; 215 | [self setViewControllers:newStack animated:isAnimated]; 216 | 217 | return removed; 218 | } else { 219 | return nil; 220 | } 221 | } 222 | 223 | - (NSArray *)popToViewController:(UIViewController *)newCurrentController animated:(BOOL)isAnimated { 224 | if ([viewControllers containsObject:newCurrentController] 225 | && [viewControllers lastObject] != newCurrentController) { 226 | 227 | NSMutableArray *newStack = [NSMutableArray arrayWithArray:viewControllers]; 228 | NSMutableArray *removedControllers = [NSMutableArray array]; 229 | 230 | NSUInteger indexOfController = [newStack indexOfObject:newCurrentController]; 231 | NSUInteger indicesToRemove = ([newStack count]-1 - indexOfController); 232 | while (indicesToRemove > 0) { 233 | [removedControllers addObject:[newStack objectAtIndex:indexOfController+1]]; 234 | [newStack removeObjectAtIndex:indexOfController+1]; 235 | indicesToRemove--; 236 | } 237 | 238 | [self setViewControllers:newStack animated:isAnimated]; 239 | 240 | return removedControllers; 241 | } else { 242 | return [NSArray array]; 243 | } 244 | } 245 | 246 | - (NSArray *)popToRootViewControllerAnimated:(BOOL)isAnimated { 247 | if ([viewControllers count] > 0) { 248 | return [self popToViewController:[viewControllers objectAtIndex:0] animated:isAnimated]; 249 | } else { 250 | return [NSArray array]; 251 | } 252 | } 253 | 254 | 255 | #pragma mark Transition Management 256 | 257 | // preconditions: 258 | // - self.topViewController is currently visible and should be removed from 259 | // the top of the navigation stack at the end of the transition 260 | // - destinationController's view is not added to the contentContainerView yet 261 | - (void)transition:(NMNavigationControllerTransition)transition 262 | toViewController:(UIViewController *)destinationController animated:(BOOL)isAnimated { 263 | 264 | // determine animation values 265 | NSTimeInterval duration = (isAnimated ? ANIMATIONDURATION : 0); 266 | 267 | // determine positions 268 | NMNavigationControllerPosition destinationStartPosition; 269 | NMNavigationControllerPosition destinationFinalPosition; 270 | NMNavigationControllerPosition currentFinalPosition; 271 | switch (transition) { 272 | case NMNavigationControllerTransitionNone: 273 | destinationStartPosition = NMNavigationControllerPositionCurrent; 274 | destinationFinalPosition = NMNavigationControllerPositionCurrent; 275 | currentFinalPosition = NMNavigationControllerPositionCurrent; 276 | break; 277 | case NMNavigationControllerTransitionPop: 278 | destinationStartPosition = NMNavigationControllerPositionBack; 279 | destinationFinalPosition = NMNavigationControllerPositionCurrent; 280 | currentFinalPosition = NMNavigationControllerPositionNext; 281 | break; 282 | case NMNavigationControllerTransitionPush: 283 | destinationStartPosition = NMNavigationControllerPositionNext; 284 | destinationFinalPosition = NMNavigationControllerPositionCurrent; 285 | currentFinalPosition = NMNavigationControllerPositionBack; 286 | break; 287 | } 288 | 289 | // prepare destination vc 290 | [self applyPostion:destinationStartPosition toViewController:destinationController]; 291 | destinationController.view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); 292 | [self.contentContainerView addSubview:destinationController.view]; 293 | if (!UIKIT_FORWARDS_APPEARANCE()) [destinationController viewWillAppear:isAnimated]; 294 | 295 | // prepare current vc 296 | UIViewController *currentController = [[self.topViewController retain] autorelease]; 297 | if (!UIKIT_FORWARDS_APPEARANCE()) [currentController viewWillDisappear:isAnimated]; 298 | 299 | // correct view controller stack 300 | [viewControllers removeLastObject]; 301 | 302 | // animate (if necessary) the view into place and send appropriate 303 | // appear / disappear messages to the involved controllers 304 | [UIView animateWithDuration:duration 305 | animations:^{ 306 | [self applyPostion:destinationFinalPosition toViewController:destinationController]; 307 | [self applyPostion:currentFinalPosition toViewController:currentController]; 308 | } 309 | completion:^(BOOL finished) { 310 | if (!UIKIT_FORWARDS_APPEARANCE()) [destinationController viewDidAppear:isAnimated]; 311 | 312 | [currentController.view removeFromSuperview]; 313 | if (transition == NMNavigationControllerTransitionPop) { 314 | currentController.nmNavigationController = nil; 315 | } 316 | if (!UIKIT_FORWARDS_APPEARANCE()) [currentController viewDidDisappear:isAnimated]; 317 | 318 | if (transition == NMNavigationControllerTransitionPush) { 319 | if ([delegate respondsToSelector:@selector(navigationController:didPushViewController:)]) { 320 | [delegate navigationController:self didPushViewController:destinationController]; 321 | } 322 | } else if (transition == NMNavigationControllerTransitionPop) { 323 | if ([delegate respondsToSelector:@selector(navigationController:didPopViewController:)]) { 324 | [delegate navigationController:self didPopViewController:currentController]; 325 | } 326 | } 327 | }]; 328 | } 329 | 330 | 331 | #pragma mark Controller Management 332 | 333 | - (void)addViewControllers:(NSArray *)vcs { 334 | for (UIViewController *vc in vcs) { 335 | vc.nmNavigationController = self; 336 | [viewControllers addObject:vc]; 337 | } 338 | } 339 | 340 | - (void)removeAllViewControllers { 341 | while ([viewControllers count] > 0) { 342 | UIViewController *bottom = [viewControllers objectAtIndex:0]; 343 | [self removeViewController:bottom]; 344 | } 345 | } 346 | 347 | - (void)removeViewControllersUpToViewController:(UIViewController *)vc { 348 | while ([viewControllers objectAtIndex:0] != vc) { 349 | UIViewController *bottom = [viewControllers objectAtIndex:0]; 350 | [self removeViewController:bottom]; 351 | } 352 | } 353 | 354 | - (void)removeViewController:(UIViewController *)vc { 355 | vc.nmNavigationController = nil; 356 | if ([vc isViewLoaded] && vc.view.superview != nil) { 357 | [vc.view removeFromSuperview]; 358 | } 359 | [viewControllers removeObject:vc]; 360 | } 361 | 362 | - (void)applyPostion:(NMNavigationControllerPosition)position toViewController:(UIViewController *)vc { 363 | CGSize contentSize = self.contentContainerView.bounds.size; 364 | 365 | switch (position) { 366 | case NMNavigationControllerPositionCurrent: 367 | vc.view.frame = CGRectMake(0, 0, contentSize.width, contentSize.height); 368 | break; 369 | case NMNavigationControllerPositionBack: 370 | vc.view.frame = CGRectMake(-contentSize.width, 0, contentSize.width, contentSize.height); 371 | break; 372 | case NMNavigationControllerPositionNext: 373 | vc.view.frame = CGRectMake(contentSize.width, 0, contentSize.width, contentSize.height); 374 | break; 375 | } 376 | } 377 | 378 | 379 | #pragma mark NMNavigationBarDelegate 380 | 381 | - (void)addNavigationBarAsSubview { 382 | if (navigationBar != nil) { 383 | navigationBarContainerView.bounds = CGRectMake(0, 0, navigationBarContainerView.bounds.size.width, navigationBar.bounds.size.height); 384 | navigationBarContainerView.center = CGPointMake(navigationBarContainerView.center.x, navigationBar.bounds.size.height/2); 385 | contentContainerView.frame = CGRectMake(0, navigationBar.bounds.size.height, self.view.bounds.size.width, self.view.bounds.size.height-navigationBar.bounds.size.height); 386 | 387 | navigationBar.frame = navigationBarContainerView.bounds; 388 | navigationBar.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); 389 | [navigationBarContainerView addSubview:navigationBar]; 390 | 391 | [navigationBar setNavigationStack:viewControllers animated:NO]; 392 | } 393 | } 394 | 395 | - (void)navigationBarDidPop:(NMNavigationBar *)bar { 396 | [self popViewControllerAnimated:YES]; 397 | } 398 | 399 | 400 | #pragma mark Interface Orientation Management 401 | 402 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 403 | BOOL result = YES; 404 | 405 | for (UIViewController* vc in viewControllers) { 406 | result = result && [vc shouldAutorotateToInterfaceOrientation:interfaceOrientation]; 407 | } 408 | 409 | return result; 410 | } 411 | 412 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 413 | for (UIViewController* vc in viewControllers) { 414 | [vc willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; 415 | } 416 | } 417 | 418 | - (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { 419 | for (UIViewController* vc in viewControllers) { 420 | [vc didRotateFromInterfaceOrientation:fromInterfaceOrientation]; 421 | } 422 | } 423 | 424 | 425 | #pragma mark State Lifecycle 426 | 427 | - (void)loadState { 428 | [super loadState]; 429 | 430 | viewControllers = [[NSMutableArray alloc] init]; 431 | } 432 | 433 | - (void)unloadState { 434 | [super unloadState]; 435 | 436 | [viewControllers release]; 437 | viewControllers = nil; 438 | 439 | [navigationBar release]; 440 | navigationBar = nil; 441 | } 442 | 443 | 444 | #pragma mark View Lifecycle 445 | 446 | - (void)viewDidLoad { 447 | [super viewDidLoad]; 448 | 449 | self.navigationBarContainerView.frame = CGRectMake(0, 0, self.view.bounds.size.width, 0); 450 | self.contentContainerView.frame = self.view.bounds; 451 | 452 | [self addNavigationBarAsSubview]; 453 | } 454 | 455 | - (void)viewWillAppear:(BOOL)animated { 456 | [super viewWillAppear:animated]; 457 | 458 | if ([viewControllers count] > 0) { 459 | UIViewController *vc = [viewControllers lastObject]; 460 | [self applyPostion:NMNavigationControllerPositionCurrent toViewController:vc]; 461 | vc.view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); 462 | [self.contentContainerView addSubview:vc.view]; 463 | if (!UIKIT_FORWARDS_APPEARANCE()) [vc viewWillAppear:animated]; 464 | } 465 | } 466 | 467 | - (void)viewDidAppear:(BOOL)animated { 468 | [super viewDidAppear:animated]; 469 | 470 | if ([viewControllers count] > 0) { 471 | UIViewController *vc = [viewControllers lastObject]; 472 | if (!UIKIT_FORWARDS_APPEARANCE()) [vc viewDidAppear:animated]; 473 | } 474 | } 475 | 476 | - (void)viewWillDisappear:(BOOL)animated { 477 | if ([viewControllers count] > 0) { 478 | UIViewController *vc = [viewControllers lastObject]; 479 | if (!UIKIT_FORWARDS_APPEARANCE()) [vc viewWillDisappear:animated]; 480 | } 481 | 482 | [super viewWillDisappear:animated]; 483 | } 484 | 485 | - (void)viewDidDisappear:(BOOL)animated { 486 | if ([viewControllers count] > 0) { 487 | UIViewController *vc = [viewControllers lastObject]; 488 | [vc.view removeFromSuperview]; 489 | if (!UIKIT_FORWARDS_APPEARANCE()) [vc viewDidDisappear:animated]; 490 | } 491 | 492 | [super viewDidDisappear:animated]; 493 | } 494 | 495 | - (void)unloadViewReferences { 496 | [super unloadViewReferences]; 497 | 498 | self.contentContainerView = nil; 499 | self.navigationBarContainerView = nil; 500 | 501 | for (UIViewController *vc in viewControllers) { 502 | if ([vc isViewLoaded]) { 503 | [vc.view removeFromSuperview]; 504 | } 505 | } 506 | } 507 | 508 | @end 509 | 510 | 511 | #define KEY_NMNAVIGATIONCONTROLLER @"NMNavigationController *nmNavigationController" 512 | 513 | @implementation UIViewController (NMNavigationControllerAdditions) 514 | 515 | #pragma mark Properties 516 | 517 | - (void)setNmNavigationController:(NMNavigationController *)vc { 518 | objc_setAssociatedObject(self, KEY_NMNAVIGATIONCONTROLLER, vc, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 519 | } 520 | 521 | - (NMNavigationController *)nmNavigationController { 522 | return objc_getAssociatedObject(self, KEY_NMNAVIGATIONCONTROLLER); 523 | } 524 | 525 | @end 526 | 527 | 528 | 529 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMTabBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMTabBar.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | #import "NMView.h" 41 | 42 | @protocol NMTabBarDelegate; 43 | 44 | 45 | 46 | // this is an abstract class and should only serve as a basis for your 47 | // implementation of a tab bar 48 | @interface NMTabBar : NMView { 49 | 50 | // State 51 | id delegate; 52 | 53 | } 54 | 55 | @property (nonatomic, assign) id delegate; 56 | 57 | 58 | // populate the view with the necessary elements to represent the view 59 | // controllers 60 | - (void)setTabsForViewControllers:(NSArray *)viewControllers; 61 | 62 | // select tabs 63 | // NSNotFound will be passed in case no tab should be selected 64 | - (void)setSelectedTab:(NSUInteger)tabIndex; 65 | 66 | @end 67 | 68 | 69 | 70 | @protocol NMTabBarDelegate 71 | 72 | - (void)tabBar:(NMTabBar *)tb didSelectTab:(NSUInteger)tabIndex; 73 | 74 | @end -------------------------------------------------------------------------------- /Libraries/NMViewController/NMTabBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMTabBar.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMTabBar.h" 39 | 40 | 41 | @implementation NMTabBar 42 | 43 | #pragma mark Properties 44 | 45 | @synthesize delegate; 46 | 47 | 48 | #pragma mark Public API 49 | 50 | - (void)setTabsForViewControllers:(NSArray *)viewControllers { 51 | // override in subclass 52 | } 53 | 54 | 55 | - (void)setSelectedTab:(NSUInteger)tabIndex { 56 | 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMTabBarController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMTabBarController.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 10.11.10. 6 | // Copyright 2010 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | #import "NMTabBar.h" 41 | #import "NMViewController.h" 42 | 43 | 44 | @protocol NMTabBarControllerDelegate; 45 | 46 | 47 | 48 | @interface NMTabBarController : NMViewController { 49 | 50 | // View 51 | UIView* viewControllerContainer; 52 | UIView *tabBarContainer; 53 | 54 | // State 55 | id delegate; 56 | NSMutableArray* viewControllers; 57 | NSUInteger selectedIndex; 58 | // - the tab bar view 59 | NMTabBar *tabBar; 60 | 61 | } 62 | 63 | @property (nonatomic, retain) IBOutlet UIView *viewControllerContainer; 64 | @property (nonatomic, retain) IBOutlet UIView *tabBarContainer; 65 | 66 | @property (nonatomic, assign) id delegate; 67 | @property (nonatomic, copy) NSArray* viewControllers; 68 | @property (nonatomic, assign) NSUInteger selectedIndex; 69 | @property (nonatomic, assign) UIViewController* selectedViewController; 70 | // currently, the tab has to be able to fill the whole width of the screen 71 | // the tab bar's height is used as is 72 | @property (nonatomic, retain) NMTabBar *tabBar; 73 | 74 | @end 75 | 76 | 77 | @protocol NMTabBarControllerDelegate 78 | 79 | @optional 80 | 81 | // only called when the user changes tabs. not called when tabBarController.selectedIndex 82 | // is reassigned 83 | - (void)tabBarController:(NMTabBarController*)vc willSelectIndex:(NSUInteger)tab; 84 | - (void)tabBarController:(NMTabBarController*)vc didSelectIndex:(NSUInteger)tab; 85 | - (void)tabBarController:(NMTabBarController*)vc popToRoot:(NSUInteger)tab; 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMTabBarController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMTabBarController.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 10.11.10. 6 | // Copyright 2010 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMTabBarController.h" 39 | 40 | 41 | #define UIKIT_FORWARDS_APPEARANCE() [UIViewController instancesRespondToSelector:@selector(automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers)] 42 | 43 | 44 | @interface NMTabBarController (Private) 45 | 46 | - (void)showCurrentViewController; 47 | - (void)hideCurrentViewController; 48 | 49 | - (void)showViewController:(UIViewController *)vc; 50 | - (void)hideViewController:(UIViewController *)vc; 51 | 52 | - (void)addTabBarAsSubview; 53 | 54 | - (NSComparisonResult)compareSystemVersionWithVersion:(NSString *)version; 55 | 56 | @end 57 | 58 | 59 | 60 | @implementation NMTabBarController 61 | 62 | #pragma mark Properties 63 | 64 | @synthesize viewControllerContainer, tabBarContainer; 65 | @synthesize delegate, viewControllers, selectedIndex, tabBar; 66 | 67 | 68 | - (void)setViewControllers:(NSArray *)vcs { 69 | // remove previous view controller 70 | [self hideCurrentViewController]; 71 | 72 | // remember new view controllers 73 | if (viewControllers != vcs) { 74 | [viewControllers release]; 75 | viewControllers = [[NSMutableArray alloc] initWithArray:vcs]; 76 | } 77 | [tabBar setTabsForViewControllers:viewControllers]; 78 | 79 | // select first view controller 80 | self.selectedIndex = 0; 81 | } 82 | 83 | - (void)setSelectedIndex:(NSUInteger)selected { 84 | if (selected == NSNotFound) { 85 | selectedIndex = selected; 86 | [tabBar setSelectedTab:selected]; 87 | } else { 88 | // remove previous view controller 89 | [self hideCurrentViewController]; 90 | 91 | // remember selected index 92 | selectedIndex = selected; 93 | 94 | // display selected view controller 95 | [tabBar setSelectedTab:selected]; 96 | [self showCurrentViewController]; 97 | } 98 | } 99 | 100 | - (void)setSelectedViewController:(UIViewController *)vc { 101 | NSUInteger selected = [viewControllers indexOfObject:vc]; 102 | 103 | if (selected != NSNotFound) { 104 | self.selectedIndex = selected; 105 | } 106 | } 107 | 108 | - (UIViewController *)selectedViewController { 109 | if (selectedIndex != NSNotFound) return [viewControllers objectAtIndex:selectedIndex]; 110 | else return nil; 111 | } 112 | 113 | - (void)setTabBar:(NMTabBar *)tb { 114 | if (tabBar != tb) { 115 | tabBar.delegate = nil; 116 | if (tabBar.superview != nil) [tabBar removeFromSuperview]; 117 | [tabBar release]; 118 | 119 | tabBar = [tb retain]; 120 | tabBar.delegate = self; 121 | } 122 | 123 | if ([self isViewLoaded]) [self addTabBarAsSubview]; 124 | } 125 | 126 | 127 | #pragma mark Helper Methods 128 | 129 | - (void)showCurrentViewController { 130 | if ([self isViewLoaded]) { 131 | [self showViewController:self.selectedViewController]; 132 | } 133 | } 134 | 135 | - (void)hideCurrentViewController { 136 | if (self.selectedViewController.view.superview != nil) { 137 | [self hideViewController:self.selectedViewController]; 138 | } else if (self.selectedIndex == NSNotFound) { 139 | for (UIViewController* vc in viewControllers) { 140 | if ([vc isViewLoaded]) { 141 | [self hideViewController:vc]; 142 | } 143 | } 144 | } 145 | } 146 | 147 | - (void)showViewController:(UIViewController *)vc { 148 | vc.view.frame = viewControllerContainer.bounds; 149 | vc.view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); 150 | 151 | // mimics the behavior of UITabBarController: 152 | // the VC's view is added to its container before the controller is sent the 153 | // -viewWillAppear: message 154 | [viewControllerContainer addSubview:self.selectedViewController.view]; 155 | if (!UIKIT_FORWARDS_APPEARANCE()) [vc viewWillAppear:NO]; 156 | if (!UIKIT_FORWARDS_APPEARANCE()) [vc viewDidAppear:NO]; 157 | } 158 | 159 | - (void)hideViewController:(UIViewController *)vc { 160 | if (!UIKIT_FORWARDS_APPEARANCE()) [vc viewWillDisappear:NO]; 161 | 162 | // mimics the behavior of UITabBarController: 163 | // the VC's view is removed from the superview before it is sent 164 | // the -viewDidDisappear: message 165 | [vc.view removeFromSuperview]; 166 | if (!UIKIT_FORWARDS_APPEARANCE()) [vc viewDidDisappear:NO]; 167 | } 168 | 169 | 170 | #pragma mark Tab Bar Management 171 | 172 | - (void)addTabBarAsSubview { 173 | if (tabBar != nil) { 174 | tabBarContainer.bounds = CGRectMake(0, 0, tabBarContainer.bounds.size.width, tabBar.bounds.size.height); 175 | tabBarContainer.center = CGPointMake(tabBarContainer.center.x, self.view.bounds.size.height-tabBar.bounds.size.height/2); 176 | viewControllerContainer.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height-tabBar.bounds.size.height); 177 | 178 | tabBar.frame = tabBarContainer.bounds; 179 | tabBar.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); 180 | [tabBarContainer addSubview:tabBar]; 181 | 182 | if (viewControllers != nil) { 183 | [tabBar setTabsForViewControllers:viewControllers]; 184 | [tabBar setSelectedTab:self.selectedIndex]; 185 | } 186 | } 187 | } 188 | 189 | - (void)tabBar:(NMTabBar *)tb didSelectTab:(NSUInteger)tabIndex { 190 | if (self.selectedIndex != tabIndex) { 191 | [delegate tabBarController:self willSelectIndex:tabIndex]; 192 | self.selectedIndex = tabIndex; 193 | [delegate tabBarController:self didSelectIndex:tabIndex]; 194 | } else { 195 | [delegate tabBarController:self popToRoot:tabIndex]; 196 | } 197 | } 198 | 199 | 200 | #pragma mark Interface Orientation Management 201 | 202 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 203 | BOOL result = YES; 204 | 205 | for (UIViewController *vc in viewControllers) { 206 | result = result && [vc shouldAutorotateToInterfaceOrientation:interfaceOrientation]; 207 | } 208 | 209 | return result; 210 | } 211 | 212 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 213 | for (UIViewController* vc in viewControllers) { 214 | [vc willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; 215 | } 216 | } 217 | 218 | - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { 219 | for (UIViewController* vc in viewControllers) { 220 | [vc didRotateFromInterfaceOrientation:fromInterfaceOrientation]; 221 | } 222 | } 223 | 224 | 225 | 226 | #pragma mark State Lifecycle 227 | 228 | - (void)unloadState { 229 | [super unloadState]; 230 | 231 | [viewControllers release]; 232 | viewControllers = nil; 233 | 234 | [tabBar release]; 235 | tabBar = nil; 236 | } 237 | 238 | 239 | #pragma mark View Lifecycle 240 | 241 | - (void)viewDidLoad { 242 | [super viewDidLoad]; 243 | 244 | [self addTabBarAsSubview]; 245 | } 246 | 247 | - (void)viewWillAppear:(BOOL)animated { 248 | [super viewWillAppear:animated]; 249 | 250 | self.selectedIndex = selectedIndex; 251 | } 252 | 253 | - (void)viewDidDisappear:(BOOL)animated { 254 | [super viewDidDisappear:animated]; 255 | 256 | [self hideCurrentViewController]; 257 | } 258 | 259 | - (void)unloadViewReferences { 260 | [super unloadViewReferences]; 261 | 262 | [tabBar removeFromSuperview]; 263 | self.viewControllerContainer = nil; 264 | self.tabBarContainer = nil; 265 | } 266 | 267 | @end 268 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMUINavigationBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMUINavigationBar.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 30.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | #import "NMNavigationBar.h" 41 | 42 | 43 | @interface NMUINavigationBar : NMNavigationBar { 44 | 45 | // View 46 | UINavigationBar *navigationBar; 47 | 48 | // State 49 | BOOL shouldNotUpdateNavigationStack; 50 | 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMUINavigationBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMUINavigationBar.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 30.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMUINavigationBar.h" 39 | 40 | 41 | @implementation NMUINavigationBar 42 | 43 | 44 | #pragma mark NMNavigationBar 45 | 46 | - (void)setNavigationStack:(NSArray *)viewControllers animated:(BOOL)isAnimated { 47 | if (!shouldNotUpdateNavigationStack) { 48 | NSMutableArray *navigationItems = [NSMutableArray array]; 49 | 50 | for (UIViewController *vc in viewControllers) { 51 | [navigationItems addObject:vc.navigationItem]; 52 | } 53 | 54 | [navigationBar setItems:navigationItems animated:isAnimated]; 55 | } else { 56 | shouldNotUpdateNavigationStack = NO; 57 | } 58 | } 59 | 60 | 61 | #pragma mark Navigation Bar Delegate 62 | 63 | - (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item { 64 | shouldNotUpdateNavigationStack = YES; 65 | [delegate navigationBarDidPop:self]; 66 | return YES; 67 | } 68 | 69 | 70 | #pragma mark View Lifecycle 71 | 72 | - (void)createView { 73 | [super createView]; 74 | 75 | self.frame = CGRectMake(0, 0, 320, 44); 76 | navigationBar = [[UINavigationBar alloc] initWithFrame:self.bounds]; 77 | navigationBar.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); 78 | navigationBar.delegate = self; 79 | [self addSubview:navigationBar]; 80 | } 81 | 82 | - (void)dealloc { 83 | [navigationBar release]; 84 | 85 | [super dealloc]; 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMUITabBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMUITabBar.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | #import "NMTabBar.h" 41 | 42 | 43 | @interface NMUITabBar : NMTabBar { 44 | 45 | // View 46 | UITabBar *tabBar; 47 | 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMUITabBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMUITabBar.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMUITabBar.h" 39 | 40 | 41 | @implementation NMUITabBar 42 | 43 | #pragma mark NMTabBar 44 | 45 | - (void)setTabsForViewControllers:(NSArray *)viewControllers { 46 | NSMutableArray *items = [NSMutableArray array]; 47 | 48 | for (UIViewController *vc in viewControllers) { 49 | [items addObject:vc.tabBarItem]; 50 | } 51 | 52 | tabBar.items = items; 53 | } 54 | 55 | - (void)setSelectedTab:(NSUInteger)tabIndex { 56 | tabBar.selectedItem = [tabBar.items objectAtIndex:tabIndex]; 57 | } 58 | 59 | 60 | #pragma mark UITabBarDelegate 61 | 62 | - (void)tabBar:(UITabBar *)tb didSelectItem:(UITabBarItem *)item { 63 | [delegate tabBar:self didSelectTab:[tabBar.items indexOfObject:item]]; 64 | } 65 | 66 | 67 | #pragma mark View Lifecycle 68 | 69 | - (void)createView { 70 | [super createView]; 71 | 72 | self.frame = CGRectMake(0, 0, 320, 49); 73 | tabBar = [[UITabBar alloc] initWithFrame:self.bounds]; 74 | tabBar.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); 75 | tabBar.delegate = self; 76 | [self addSubview:tabBar]; 77 | } 78 | 79 | - (void)dealloc { 80 | [tabBar release]; 81 | 82 | [super dealloc]; 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewController.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import 39 | 40 | 41 | /** 42 | * Introduction 43 | * ============= 44 | * 45 | * Each UIViewController essentially defines a screen worth of information that 46 | * can be displayed in your app. 47 | * 48 | * Since memory on a mobile device is low (compared to desktop environments) and 49 | * since the representation of a screen's UI can use big amounts of memory 50 | * (think of images and videos), UIViewController handles the automatic creation 51 | * and destruction of the screen's UI representation. 52 | * 53 | * This is very handy when you need to manage different screens in your app 54 | * since it allows you to keep all of the screens objects (the respective 55 | * UIViewControllers) in memory, while dynamically loading / unloading their 56 | * views whenever they are required. 57 | * 58 | * Dynamically loading / unloading views of UIViewController objects comes at a 59 | * cost, however: at any point in time when the controller's screen is not 60 | * visible, the view of the controller can be unloaded. Thus, the controller has 61 | * to be prepared to restore the view's state. For example, imagine an app where 62 | * you have a list to choose an item from (screen 1), a detail view for a 63 | * selected item (screen 2) and a slideshow of images belonging to an item 64 | * (screen 3). When navigating from screen 2 to screen 3, the slideshow might 65 | * load a lot of images into memory, causing the view of screen 2 to be 66 | * unloaded. When the user chooses to navigate back from screen 3 to screen 2, 67 | * the view of screen 2 is loaded from scratch. The new view of screen 2 no 68 | * longer presents the information that was previously visible on screen 2 69 | * (that view had been unloaded) unless you explicitly refresh the view to 70 | * display the information of the selected item. This case has to manually be 71 | * taken care of when implementing a UIViewController. 72 | * 73 | * This behavior boils down to two different memory lifecycles: 74 | * 1. State Lifecycle: Memory required from creation of the UIViewController to 75 | * its destruction. 76 | * 2. View Lifecycle: Memory required from loading of the UIViewController's 77 | * view to when it's unloaded. 78 | * 79 | * In the example above, information about the selected item would have to be 80 | * managed in the "State Lifecycle" as the information about the selected item 81 | * has to be present even after the view has been unloaded so that it can be 82 | * used to repopulate the view with the item's data. 83 | * 84 | * Individual UIView objects required to display the item's data, however, would 85 | * have to be manged in the "View Lifecycle" as these are only required while 86 | * the view is loaded. 87 | * 88 | * 89 | * NMViewController's Memory Lifecycles 90 | * ===================================== 91 | * 92 | * UIViewController can make it rather hard to see where these separate 93 | * lifecycles should be managed. We've therefore created a UIViewController 94 | * subclass - NMViewController - which provides a clearly defined way of 95 | * managing the separate lifecycles. Your controllers can inherit from 96 | * NMViewController and benefit from the provided lifecycle methods. 97 | * 98 | * 1. State Lifecycle 99 | * 100 | * Whenever an NMViewController is created (regardless of the init method used), 101 | * its -loadState method is called, giving the opportunity to initialize any 102 | * state information required. 103 | * 104 | * Whenever an NMViewController is destroyed, its -unloadState method is called 105 | * so that any state memory can be reclaimed. This typically includes any memory 106 | * prepared in -loadState and state data that has been provided externally using 107 | * properties. 108 | * 109 | * 2. View Lifecycle 110 | * 111 | * NMViewController relies on the fact that you either implement -loadView in 112 | * your subclass to programmatically create the UI of your screen or that you 113 | * override -viewDidLoad to do any post-initialization after your view has been 114 | * loaded from a nib file. 115 | * 116 | * Whenever an NMViewController's view is unloaded (either when the controller 117 | * is destroyed or when its -viewDidUnload method was called), the 118 | * -unloadViewReferences method is called, giving you the opportunity to 119 | * release any memory that you have explicitly (eg. by creating and retaining 120 | * UIView objects in -loadView or -viewDidLoad) or implicitly (eg. by assigning 121 | * objects to IBOutlets during nib loading) retained. 122 | * 123 | * As another example of what has to be unloaded in -unloadViewReferences, 124 | * suppose in the example above your slideshow screen contains a scroll view 125 | * into which you dynamically add UIImageView objects in your -viewDidLoad 126 | * method. Now you need to keep track of those UIImageView objects in an NSArray 127 | * for easy manipulation of their images. In that case, the UIImageView objects 128 | * have to be removed from the array in your -unloadViewReferences method. 129 | * 130 | * 131 | * Cached Data 132 | * ============ 133 | * 134 | * As a bonus, NMViewController calls the -unloadCachedData method whenever a 135 | * memory warning is received. You can implement this method to release any data 136 | * that you have cached during the lifetime of the controller but which you do 137 | * not need to bring the controller back into the state that the user expects. 138 | * 139 | * In the example above, assume that the slideshow (screen 3) displays a lot of 140 | * large images. Whenever the user scrolls to the next image in the slideshow, 141 | * it is loaded into memory and displayed but the images that the user has 142 | * already seen are kept in memory so that no loading time occurs whenever the 143 | * user decides to swipe back to a previously visited image. 144 | * 145 | * In that case, a memory warning can easily occur while the user keeps viewing 146 | * more images. In that case, NMViewController calls -unloadCachedData, giving 147 | * your subclass the chance of cleaning up any image that is not currently 148 | * displayed on screen. Those images can easily be reloaded in case the user 149 | * goes back to a previous image, therefore they can safely be released when 150 | * memory is low. 151 | * 152 | * This can also apply to data that you would consider to belong to the "State 153 | * Lifecyle": imagine that you load the images into NSData objects before you 154 | * create UIImages. In that case, you should let go of both objects when 155 | * -unloadCachedData is called, not only the UIImage objects. 156 | * 157 | * 158 | * Remarks 159 | * ======== 160 | * 161 | * 1. Make sure that you call the super implementation of any NMViewController 162 | * method that you implement in your custom subclass. 163 | */ 164 | @interface NMViewController : UIViewController { 165 | 166 | } 167 | 168 | 169 | // Memory Lifecycles 170 | 171 | // 1. State Lifecycle 172 | 173 | // Initialize / Release any state your controller is using that must be present 174 | // from creation to destruction of the controller 175 | - (void)loadState; 176 | - (void)unloadState; 177 | 178 | 179 | // 2. View Lifecycle 180 | 181 | // Release any view references you retained during loadView / viewDidLoad. 182 | // You need to release *any* objects that pertain 183 | - (void)unloadViewReferences; 184 | 185 | 186 | // Cached Data 187 | 188 | // Optional: If your controller uses a cache for some of the data it needs to 189 | // display / work with, you must release any of the cached data that is not 190 | // needed at the moment and which can be recreated in this method. 191 | - (void)unloadCachedData; 192 | 193 | @end 194 | -------------------------------------------------------------------------------- /Libraries/NMViewController/NMViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NMViewController.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | // 8 | 9 | /* 10 | * The BSD License 11 | * http://www.opensource.org/licenses/bsd-license.php 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, this 17 | * list of conditions and the following disclaimer. 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * - Neither the name of NEXT Munich GmbH nor the names of its contributors may 22 | * be used to endorse or promote products derived from this software without 23 | * specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #import "NMViewController.h" 39 | 40 | 41 | @implementation NMViewController 42 | 43 | #pragma mark Properties 44 | 45 | 46 | #pragma mark Initializers 47 | 48 | - (id) init { 49 | if ((self = [super init])) { 50 | [self loadState]; 51 | } 52 | 53 | return self; 54 | } 55 | 56 | - (id) initWithCoder:(NSCoder *)aDecoder { 57 | if ((self = [super initWithCoder:aDecoder])) { 58 | [self loadState]; 59 | } 60 | 61 | return self; 62 | } 63 | 64 | - (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 65 | if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { 66 | [self loadState]; 67 | } 68 | 69 | return self; 70 | } 71 | 72 | 73 | #pragma mark State Management 74 | 75 | - (void) loadState { } 76 | 77 | 78 | #pragma mark Memory Management Callbacks 79 | 80 | - (void) unloadState { } 81 | 82 | - (void) unloadViewReferences { } 83 | 84 | - (void) unloadCachedData { } 85 | 86 | 87 | #pragma mark Memory Management 88 | 89 | - (void)didReceiveMemoryWarning { 90 | [super didReceiveMemoryWarning]; 91 | 92 | [self unloadCachedData]; 93 | } 94 | 95 | - (void)viewDidUnload { 96 | [super viewDidUnload]; 97 | 98 | [self unloadViewReferences]; 99 | } 100 | 101 | - (void)dealloc { 102 | [self unloadViewReferences]; 103 | [self unloadState]; 104 | 105 | [super dealloc]; 106 | } 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /NMViewController_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'NMViewController' target in the 'NMViewController' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Update 2 | 3 | Important: iOS 5 changes the way view appearance callbacks are sent to child 4 | view controllers. On previous iOS versions, a custom container view 5 | controller was responsible for notifying its child containers of view 6 | appearance (-viewWillAppear:, -viewDidAppear:, -viewWillDisappear:, 7 | -viewDidDisappear:). Now this is handled automatically by iOS 5 which leads 8 | to twice as many calls when working with NMNavigationController or 9 | NMTabBarController. This has been fixed in the latest update. 10 | 11 | 12 | # Introduction 13 | 14 | iOS provides a lot of convenience classes to integrate common UI metaphors into 15 | your Apps: UITabBarController, UINavigationController and UIPopoverController 16 | amongst others. 17 | 18 | Most of these classes lack the skinnability that many people require when 19 | creating branded apps. The NMViewController repository gathers custom 20 | implementations of common UIViewController subclasses which allow for a custom 21 | look and feel. And, since they are open source, if their implementation does 22 | not meet your requirements, you can change their implementation and work them 23 | your own way. 24 | 25 | 26 | # NMViewController 27 | 28 | Even though this class has a very simple (some might call it empty) implementation 29 | it can serve as a great help to people new to iOS development. UIViewController 30 | is rather complex to understand since it allows for the existance of the controller 31 | without a loaded view. Even more so, the view may be unloaded if necessary, a case 32 | that's often neglected by newbies. 33 | 34 | NMViewController documents the memory lifecycles involved in dealing with 35 | UIViewController and provides simple convenience methods that can be overriden and 36 | which will provide a clear way of managing controller state vs. view state. 37 | 38 | Even if you don't want to use the class, pass the documentation to somebody new to 39 | iOS - it's going to help. 40 | 41 | 42 | # NMTabBarController 43 | 44 | A re-implementation of a UITabBarController which allows for a custom look and feel 45 | of the tab bar. It comes with a default implementation of NMTabBar called NMUITabBar 46 | that provides the iOS default look and feel. 47 | 48 | The architectural decision behind NMTabBarController was to free the implementation 49 | from an object like UITabBarItem. Without the contraints of the data that can be 50 | communicated using UITabBarItem, an NMTabBar hosted by NMTabBarController can display 51 | its tabs in whichever way it chooses. Here are some examples of how it can be 52 | implemented: 53 | 54 | 1. NMUITabBar just reuses UITabBar and UITabBarItems to implement the look and feel 55 | of the tab bar. 56 | 2. SwitchTabBar makes the assumption that exactly two UIViewControllers will be added 57 | to the NMTabBarController and allows switching between the two. 58 | 3. An implementation could make use of a different property defined on your custom 59 | UIViewControllers and will use that property for configuring the look of the items 60 | on the tab bar. 61 | 4. An implementation could use the data stored in UITabBarItem and display it in a 62 | completely different fashion. 63 | 64 | ... the sky's the limit! 65 | 66 | One feature explicitly not implemented is customization of the NMTabBarController's 67 | tabs. We've never had the necessity to make use of that feature - therefore it's not 68 | available. 69 | 70 | NMTabBarController explicitly handles NMTabBars of different heights, correctly 71 | resizing the content area as necessary. When adding your UIViewControllers' views to 72 | its content area, it sets their respective view's autoresizingMask so that it fills 73 | the content area whenever it's resized (eg. during a rotation). 74 | 75 | Check out the sample targets NMUITabBar and SwitchTabBar to see two completely 76 | different tab bar implementations in action. Rotate the device to see the hosted 77 | UIViewController's autoresize to the new orientation. 78 | 79 | 80 | # NMNavigationController 81 | 82 | Finally, a re-implementation of UINavigationController is now available, too. Similar 83 | to NMTabBarController, NMNavigationController allows you to use custom navigation 84 | bars with a custom look and feel. Like NMUITabBar, NMUINavigationBar provides an 85 | implementation of NMNavigationBar with the default iOS look and feel. 86 | 87 | Most of the methods available on a UINavigationController are available on 88 | NMNavigationController, too. The delegate protocol of NMNavigationController is a 89 | little rough around the edges but provides you with the most fundamental 90 | notifications. 91 | 92 | 93 | # Future 94 | 95 | Re-implementations of UITabBarController and UINavigationController have been the 96 | classes we've used in a couple of projects now. As for other UIViewControllers, 97 | we'll implement them as the need arises. 98 | -------------------------------------------------------------------------------- /Resources/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextmunich/NMViewController/e77bae748f02c2a1e454dded904592d33aa2eed1/Resources/Icon-72.png -------------------------------------------------------------------------------- /Resources/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextmunich/NMViewController/e77bae748f02c2a1e454dded904592d33aa2eed1/Resources/Icon-Small-50.png -------------------------------------------------------------------------------- /Resources/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextmunich/NMViewController/e77bae748f02c2a1e454dded904592d33aa2eed1/Resources/Icon-Small.png -------------------------------------------------------------------------------- /Resources/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | NMViewController 4 | 5 | Created by Benjamin Broll on 27.05.11. 6 | Copyright 2011 NEXT Munich GmbH. The App Agency. All rights reserved. 7 | */ 8 | -------------------------------------------------------------------------------- /Resources/NMViewController-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | de_DE 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | Icon-72.png 13 | CFBundleIconFiles 14 | 15 | Icon-72.png 16 | Icon-Small.png 17 | Icon-Small-50.png 18 | 19 | CFBundleIdentifier 20 | com.next-munich.prototyping.${PRODUCT_NAME:rfc1034identifier} 21 | CFBundleInfoDictionaryVersion 22 | 6.0 23 | CFBundleName 24 | ${PRODUCT_NAME} 25 | CFBundlePackageType 26 | APPL 27 | CFBundleShortVersionString 28 | 1.0 29 | CFBundleSignature 30 | ???? 31 | CFBundleVersion 32 | ${CURRENT_PROJECT_VERSION} 33 | LSRequiresIPhoneOS 34 | 35 | NSMainNibFile 36 | MainWindow 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Resources/UnitTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.next-munich.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleSignature 16 | ???? 17 | CFBundleVersion 18 | ${CURRENT_PROJECT_VERSION} 19 | CFBundleShortVersionString 20 | 1.0 21 | 22 | 23 | -------------------------------------------------------------------------------- /Resources/iTunesArtwork: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextmunich/NMViewController/e77bae748f02c2a1e454dded904592d33aa2eed1/Resources/iTunesArtwork -------------------------------------------------------------------------------- /UnitTests/TestSuite.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestSuite.h 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 24.06.10. 6 | // Copyright 2010 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | // See Also: http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/135-Unit_Testing_Applications/unit_testing_applications.html 9 | 10 | #import 11 | #import 12 | 13 | 14 | @interface TestSuite : SenTestCase { 15 | 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /UnitTests/TestSuite.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestSuite.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 24.06.10. 6 | // Copyright 2010 NEXT Munich. The App Agency. All rights reserved. 7 | // 8 | 9 | #import "TestSuite.h" 10 | 11 | 12 | @implementation TestSuite 13 | 14 | - (void) testSomething { 15 | STAssertTrue(YES, @""); 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // NMViewController 4 | // 5 | // Created by Benjamin Broll on 27.05.11. 6 | // Copyright 2011 NEXT Munich GmbH. The App Agency. 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 | --------------------------------------------------------------------------------