├── BSPanViewController.podspec ├── BSPanViewController ├── BSPanViewController.h └── BSPanViewController.m ├── Example ├── Example.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── Example.xccheckout │ │ └── xcuserdata │ │ │ └── simonbs.xcuserdatad │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── WorkspaceSettings.xcsettings │ └── xcuserdata │ │ └── simonbs.xcuserdatad │ │ └── xcschemes │ │ ├── Example.xcscheme │ │ └── xcschememanagement.plist ├── Example │ ├── Example-Info.plist │ ├── Example-Prefix.pch │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── LaunchImage.launchimage │ │ │ └── Contents.json │ │ ├── LeftBackground.imageset │ │ │ ├── Contents.json │ │ │ └── LeftBackground.png │ │ ├── Menu.imageset │ │ │ ├── Contents.json │ │ │ ├── Menu.png │ │ │ └── Menu@2x.png │ │ └── RightBackground.imageset │ │ │ ├── Contents.json │ │ │ └── RightBackground.png │ ├── Source │ │ └── Controllers │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── LeftViewController.h │ │ │ ├── LeftViewController.m │ │ │ ├── MainViewController.h │ │ │ ├── MainViewController.m │ │ │ ├── RightViewController.h │ │ │ ├── RightViewController.m │ │ │ ├── SideViewController.h │ │ │ └── SideViewController.m │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m └── ExampleTests │ ├── ExampleTests-Info.plist │ ├── ExampleTests.m │ └── en.lproj │ └── InfoPlist.strings ├── LICENSE.txt ├── README.md └── screenshot.gif /BSPanViewController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'BSPanViewController' 3 | s.version = '1.0.1' 4 | s.homepage = 'https://github.com/simonbs/BSPanViewController' 5 | s.authors = { 'Simon Støvring' => 'simon@intuitaps.dk' } 6 | s.license = 'MIT' 7 | s.summary = 'A take on the sliding controllers which can optionally move the status bar along with the main view.' 8 | s.source = { :git => 'https://github.com/simonbs/BSPanViewController.git', :tag => '1.0.1' } 9 | s.source_files = 'BSPanViewController/*.{h,m}' 10 | s.ios.deployment_target = '7.0' 11 | s.requires_arc = true 12 | end -------------------------------------------------------------------------------- /BSPanViewController/BSPanViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BSPanViewController.h 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * Specifies a side which is revealed. 13 | */ 14 | typedef NS_ENUM(NSInteger, BSSide) { 15 | /** 16 | * No side is revealed. 17 | */ 18 | BSSideUnknown = -1, 19 | /** 20 | * Left side is revelaed. 21 | */ 22 | BSSideLeft = 0, 23 | /** 24 | * Right side is revealed. 25 | */ 26 | BSSideRight, 27 | }; 28 | 29 | /** 30 | * Specifies why the user is dragging. 31 | * This can also be used to detect what will happen if the user stops the pan gesture. 32 | */ 33 | typedef NS_ENUM(NSInteger, BSPanIntention) { 34 | /** 35 | * No intention is specified. 36 | */ 37 | BSPanIntentionUnknown = -1, 38 | /** 39 | * Opening intention. If the user stops the pan gesture, the side will be opened. 40 | */ 41 | BSPanIntentionOpening = 0, 42 | /** 43 | * Closing intention. If the user stops the pan gesture, side will be closed. 44 | */ 45 | BSPanIntentionClosing, 46 | }; 47 | 48 | @protocol BSPanViewControllerDelegate; 49 | 50 | /** 51 | * Controller which has a left and right side which can be opened and closed either 52 | * using a pan gesture or programmatically. 53 | */ 54 | @interface BSPanViewController : UIViewController 55 | 56 | /** 57 | * The delegate which should be notified of events. 58 | */ 59 | @property (nonatomic, weak) id delegate; 60 | 61 | /** 62 | * The current side being opened or closed. The value is reset when the side is closed. 63 | */ 64 | @property (nonatomic, readonly) BSSide side; 65 | 66 | /** 67 | * Whether or not a side is currently opened. 68 | * Refer to the side to figure out which side is opened. 69 | * 70 | * @see BSSide 71 | */ 72 | @property (nonatomic, readonly, getter = isOpened) BOOL opened; 73 | 74 | /** 75 | * The controller which can be dragged. 76 | */ 77 | @property (nonatomic, strong) UIViewController *mainController; 78 | 79 | /** 80 | * Controller disabled when the main controller is dragged to the left. 81 | * Note that if this controller is set and you wish to be able to open 82 | * and close the side using a pan gesture this must be enabled. 83 | * 84 | * @see leftPanEnabled 85 | */ 86 | @property (nonatomic, strong) UIViewController *leftController; 87 | 88 | /** 89 | * Controller disabled when the main controller is dragged to the right. 90 | * Note that if this controller is set and you wish to be able to open 91 | * and close the side using a pan gesture this must be enabled. 92 | * 93 | * @see rightPanEnabled 94 | */ 95 | @property (nonatomic, strong) UIViewController *rightController; 96 | 97 | /** 98 | * Specifies whether or not the user should be able to open and close 99 | * the left controller using the pan gesture. 100 | */ 101 | @property (nonatomic, assign, getter = isLeftPanEnabled) BOOL leftPanEnabled; 102 | 103 | /** 104 | * Width of the area which will trigger the pan gesture when opening the left side. 105 | */ 106 | @property (nonatomic, assign) CGFloat leftPanSize; 107 | 108 | /** 109 | * Amount the left side should be revealed when the side is opened. 110 | */ 111 | @property (nonatomic, assign) CGFloat leftOpenAmount; 112 | 113 | /** 114 | * Duration of the animation when opening the left side, 115 | */ 116 | @property (nonatomic, assign) NSTimeInterval leftOpenAnimationDuration; 117 | 118 | /** 119 | * Amount of damping in the animation played when opening the left side. 120 | */ 121 | @property (nonatomic, assign) CGFloat leftOpenSpringDamping; 122 | 123 | /** 124 | * Amount of velocity in the animation played when opening the left side. 125 | */ 126 | @property (nonatomic, assign) CGFloat leftOpenSpringVelocity; 127 | 128 | /** 129 | * Duration of the animation when closing the left side, 130 | */ 131 | @property (nonatomic, assign) NSTimeInterval leftCloseAnimationDuration; 132 | 133 | /** 134 | * Amount of damping in the animation played when closing the left side. 135 | */ 136 | @property (nonatomic, assign) CGFloat leftCloseSpringDamping; 137 | 138 | /** 139 | * Amount of velocity in the animation played when closing the left side. 140 | */ 141 | @property (nonatomic, assign) CGFloat leftCloseSpringVelocity; 142 | 143 | /** 144 | * Parallax amount of the left side. A value between 0 and 1. 145 | * A value of 0 means that the side will not be parallaxed and value of 1 means 146 | * that the side will scroll with the same speed as the main controller. 147 | * A value of 0.50 means the view is shifted half of the amount the side 148 | * should be opened and thus it scrolls half speed of the main controller. 149 | */ 150 | @property (nonatomic, assign) CGFloat leftParallaxAmount; 151 | 152 | /** 153 | * Specifies whether or not the status bar should be moved along with 154 | * the main controller or it should stay at its default position. 155 | */ 156 | @property (nonatomic, assign) BOOL openingLeftMovesStatusBar; 157 | 158 | /** 159 | * Color of the shadow on the main controller when revealing the left side. 160 | */ 161 | @property (nonatomic, strong) UIColor *leftShadowColor; 162 | 163 | /** 164 | * Opacity of the shadow on the main controller when revealing the left side. 165 | */ 166 | @property (nonatomic, assign) CGFloat leftShadowOpacity; 167 | 168 | /** 169 | * Radius of the shadow on the main controller when revealing the left side. 170 | */ 171 | @property (nonatomic, assign) CGFloat leftShadowRadius; 172 | 173 | /** 174 | * Offset of the shadow on the main controller when revealing the left side. 175 | */ 176 | @property (nonatomic, assign) CGSize leftShadowOffset; 177 | 178 | /** 179 | * Specifies whether or not the left side should be closed when tapping 180 | * the main controller while the side is opened. 181 | */ 182 | @property (nonatomic, assign) BOOL leftTapToCloseEnabled; 183 | 184 | /** 185 | * Specifies whether or not the user should be able to open and close 186 | * the right controller using the pan gesture. 187 | */ 188 | @property (nonatomic, assign, getter = isRightPanEnabled) BOOL rightPanEnabled; 189 | 190 | /** 191 | * Width of the area which will trigger the pan gesture when opening the right side. 192 | */ 193 | @property (nonatomic, assign) CGFloat rightPanSize; 194 | 195 | /** 196 | * Amount the right side should be revealed when the side is opened. 197 | */ 198 | @property (nonatomic, assign) CGFloat rightOpenAmount; 199 | 200 | /** 201 | * Duration of the animation when opening the right side, 202 | */ 203 | @property (nonatomic, assign) NSTimeInterval rightOpenAnimationDuration; 204 | 205 | /** 206 | * Amount of damping in the animation played when opening the right side. 207 | */ 208 | @property (nonatomic, assign) CGFloat rightOpenSpringDamping; 209 | 210 | /** 211 | * Amount of velocity in the animation played when opening the right side. 212 | */ 213 | @property (nonatomic, assign) CGFloat rightOpenSpringVelocity; 214 | 215 | /** 216 | * Duration of the animation when closing the right side, 217 | */ 218 | @property (nonatomic, assign) NSTimeInterval rightCloseAnimationDuration; 219 | 220 | /** 221 | * Amount of damping in the animation played when closing the right side. 222 | */ 223 | @property (nonatomic, assign) CGFloat rightCloseSpringDamping; 224 | 225 | /** 226 | * Amount of velocity in the animation played when closing the right side. 227 | */ 228 | @property (nonatomic, assign) CGFloat rightCloseSpringVelocity; 229 | 230 | /** 231 | * Parallax amount of the right side. A value between 0 and 1. 232 | * A value of 0 means that the side will not be parallaxed and value of 1 means 233 | * that the side will scroll with the same speed as the main controller. 234 | * A value of 0.50 means the view is shifted half of the amount the side 235 | * should be opened and thus it scrolls half speed of the main controller. 236 | */ 237 | @property (nonatomic, assign) CGFloat rightParallaxAmount; 238 | 239 | /** 240 | * Specifies whether or not the status bar should be moved along with 241 | * the main controller or it should stay at its default position. 242 | */ 243 | @property (nonatomic, assign) BOOL openingRightMovesStatusBar; 244 | 245 | /** 246 | * Color of the shadow on the main controller when revealing the right side. 247 | */ 248 | @property (nonatomic, strong) UIColor *rightShadowColor; 249 | 250 | /** 251 | * Opacity of the shadow on the main controller when revealing the right side. 252 | */ 253 | @property (nonatomic, assign) CGFloat rightShadowOpacity; 254 | 255 | /** 256 | * Radius of the shadow on the main controller when revealing the right side. 257 | */ 258 | @property (nonatomic, assign) CGFloat rightShadowRadius; 259 | 260 | /** 261 | * Offset of the shadow on the main controller when revealing the right side. 262 | */ 263 | @property (nonatomic, assign) CGSize rightShadowOffset; 264 | 265 | /** 266 | * Specifies whether or not the right side should be closed when tapping 267 | * the main controller while the side is opened. 268 | */ 269 | @property (nonatomic, assign) BOOL rightTapToCloseEnabled; 270 | 271 | /** 272 | * Open or close the left side depending on its current state. 273 | */ 274 | - (void)toggleLeft; 275 | 276 | /** 277 | * Open or close the right side depending on its current state. 278 | */ 279 | - (void)toggleRight; 280 | 281 | /** 282 | * Open the left side. 283 | */ 284 | - (void)openLeft; 285 | 286 | /** 287 | * Close the left side. 288 | */ 289 | - (void)closeLeft; 290 | 291 | /** 292 | * Open the right side, 293 | */ 294 | - (void)openRight; 295 | 296 | /** 297 | * Close the right side. 298 | */ 299 | - (void)closeRight; 300 | 301 | @end 302 | 303 | @protocol BSPanViewControllerDelegate 304 | @optional 305 | /** 306 | * Called when a side is opened. 307 | * 308 | * @param controller The pan controller which opened the side. 309 | * @param side Side which was opened. 310 | * 311 | * @see BSSide 312 | */ 313 | - (void)panViewController:(BSPanViewController *)controller didOpenSide:(BSSide)side; 314 | 315 | /** 316 | * Called when a side is closed. 317 | * 318 | * @param controller The pan controller which closed the side. 319 | * @param side Side which was closed. 320 | * 321 | * @see BSSide 322 | */ 323 | - (void)panViewController:(BSPanViewController *)controller didCloseSide:(BSSide)side; 324 | 325 | /** 326 | * Called when the main controller is dragged. 327 | * 328 | * @param controller The pan controller which closed the side. 329 | * @param side Side the controller was dragged in. 330 | * @param percentage Amount the side is revelead. 331 | * @param intention Intention of the user. 332 | * 333 | * @see BSSide 334 | * @see BSPanIntention 335 | */ 336 | - (void)panViewController:(BSPanViewController *)controller didDragSide:(BSSide)side toPercentage:(CGFloat)percentage withIntention:(BSPanIntention)intention; 337 | @end 338 | -------------------------------------------------------------------------------- /BSPanViewController/BSPanViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BSPanViewController.m 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import "BSPanViewController.h" 10 | 11 | #define BSDefaultLeftPanSize 30.0f 12 | #define BSDefaultLeftOpenAmount 270.0f 13 | #define BSDefaultLeftOpenAnimationDuration 0.35f 14 | #define BSDefaultLeftOpenSpringDamping 0.50f 15 | #define BSDefaultLeftOpenSpringVelocity 0.50f 16 | #define BSDefaultLeftCloseAnimationDuration 0.25f 17 | #define BSDefaultLeftCloseSpringDamping 1.0f 18 | #define BSDefaultLeftCloseSpringVelocity 0.0f 19 | #define BSDefaultLeftParallaxAmount 0.35f 20 | #define BSDefaultOpeningLeftMovesStatusBar YES 21 | #define BSDefaultLeftShadowColor [UIColor blackColor] 22 | #define BSDefaultLeftShadowOpacity 1.0f 23 | #define BSDefaultLeftShadowRadius 10.0f 24 | #define BSDefaultLeftShadowOffset CGSizeMake(-3.0f, 0.0f) 25 | #define BSDefaultLeftTapToCloseEnabled YES 26 | 27 | #define BSDefaultRightPanSize 30.0f 28 | #define BSDefaultRightOpenAmount 270.0f 29 | #define BSDefaultRightOpenAnimationDuration 0.35f 30 | #define BSDefaultRightOpenSpringDamping 0.50f 31 | #define BSDefaultRightOpenSpringVelocity 0.50f 32 | #define BSDefaultRightCloseAnimationDuration 0.25f 33 | #define BSDefaultRightCloseSpringDamping 1.0f 34 | #define BSDefaultRightCloseSpringVelocity 0.0f 35 | #define BSDefaultRightParallaxAmount 0.35f 36 | #define BSDefaultOpeningRightMovesStatusBar YES 37 | #define BSDefaultRightShadowColor [UIColor blackColor] 38 | #define BSDefaultRightShadowOpacity 1.0f 39 | #define BSDefaultRightShadowRadius 10.0f 40 | #define BSDefaultRightShadowOffset CGSizeMake(3.0f, 0.0f) 41 | #define BSDefaultRightTapToCloseEnabled YES 42 | 43 | @interface BSPanViewController () 44 | @property (nonatomic, assign) CGPoint panPreviousLocation; 45 | @property (nonatomic, assign) BSPanIntention panIntention; 46 | @property (nonatomic, assign) BSSide side; 47 | @property (nonatomic, assign, getter = isOpened) BOOL opened; 48 | @property (nonatomic, strong) UIView *statusBarContainer; 49 | @property (nonatomic, assign) CGRect initialMainControllerFrame; 50 | @property (nonatomic, assign, getter = isStatusBarFaked) BOOL statusBarFaked; 51 | @property (nonatomic, assign) BOOL hideStatusBar; // Used when UIViewControllerBasedStatusBarAppearance is true 52 | @end 53 | 54 | @implementation BSPanViewController 55 | 56 | #pragma mark - 57 | #pragma mark Lifecycle 58 | 59 | - (id)init 60 | { 61 | if (self = [super init]) 62 | { 63 | self.side = BSSideUnknown; 64 | self.panIntention = BSPanIntentionUnknown; 65 | 66 | self.leftPanSize = BSDefaultLeftPanSize; 67 | self.leftOpenAmount = BSDefaultLeftOpenAmount; 68 | self.leftOpenAnimationDuration = BSDefaultLeftOpenAnimationDuration; 69 | self.leftOpenSpringDamping = BSDefaultLeftOpenSpringDamping; 70 | self.leftOpenSpringVelocity = BSDefaultLeftOpenSpringVelocity; 71 | self.leftCloseAnimationDuration = BSDefaultLeftCloseAnimationDuration; 72 | self.leftCloseSpringDamping = BSDefaultLeftCloseSpringDamping; 73 | self.leftCloseSpringVelocity = BSDefaultLeftCloseSpringVelocity; 74 | self.leftParallaxAmount = BSDefaultLeftParallaxAmount; 75 | self.openingLeftMovesStatusBar = BSDefaultOpeningLeftMovesStatusBar; 76 | self.leftShadowColor = BSDefaultLeftShadowColor; 77 | self.leftShadowOpacity = BSDefaultLeftShadowOpacity; 78 | self.leftShadowRadius = BSDefaultLeftShadowRadius; 79 | self.leftShadowOffset = BSDefaultLeftShadowOffset; 80 | self.leftTapToCloseEnabled = BSDefaultLeftTapToCloseEnabled; 81 | 82 | self.rightPanSize = BSDefaultRightPanSize; 83 | self.rightOpenAmount = BSDefaultRightOpenAmount; 84 | self.rightOpenAnimationDuration = BSDefaultRightOpenAnimationDuration; 85 | self.rightOpenSpringDamping = BSDefaultRightOpenSpringDamping; 86 | self.rightOpenSpringVelocity = BSDefaultRightOpenSpringVelocity; 87 | self.rightCloseAnimationDuration = BSDefaultRightCloseAnimationDuration; 88 | self.rightCloseSpringDamping = BSDefaultRightCloseSpringDamping; 89 | self.rightCloseSpringVelocity = BSDefaultRightCloseSpringVelocity; 90 | self.rightParallaxAmount = BSDefaultRightParallaxAmount; 91 | self.openingRightMovesStatusBar = BSDefaultOpeningRightMovesStatusBar; 92 | self.rightShadowColor = BSDefaultRightShadowColor; 93 | self.rightShadowOpacity = BSDefaultRightShadowOpacity; 94 | self.rightShadowRadius = BSDefaultRightShadowRadius; 95 | self.rightShadowOffset = BSDefaultRightShadowOffset; 96 | self.rightTapToCloseEnabled = BSDefaultRightTapToCloseEnabled; 97 | } 98 | 99 | return self; 100 | } 101 | 102 | - (void)viewDidLoad 103 | { 104 | [super viewDidLoad]; 105 | 106 | UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; 107 | panGesture.delegate = self; 108 | [self.view addGestureRecognizer:panGesture]; 109 | 110 | UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; 111 | tapGesture.delegate = self; 112 | [self.view addGestureRecognizer:tapGesture]; 113 | } 114 | 115 | - (void)dealloc 116 | { 117 | _delegate = nil; 118 | _mainController = nil; 119 | _leftController = nil; 120 | _rightController = nil; 121 | _statusBarContainer = nil; 122 | _leftShadowColor = nil; 123 | _rightShadowColor = nil; 124 | } 125 | 126 | - (BOOL)prefersStatusBarHidden 127 | { 128 | return self.hideStatusBar; 129 | } 130 | 131 | #pragma mark - 132 | #pragma mark Public Accessors 133 | 134 | - (void)setMainController:(UIViewController *)mainController 135 | { 136 | if (mainController != _mainController) 137 | { 138 | if (_mainController) 139 | { 140 | [_mainController removeFromParentViewController]; 141 | [_mainController.view removeFromSuperview]; 142 | } 143 | 144 | if (mainController) 145 | { 146 | [self addChildViewController:mainController]; 147 | [self.view addSubview:mainController.view]; 148 | [self.view bringSubviewToFront:mainController.view]; 149 | } 150 | 151 | _mainController = mainController; 152 | } 153 | } 154 | 155 | - (void)setLeftController:(UIViewController *)leftController 156 | { 157 | if (leftController != _leftController) 158 | { 159 | if (_leftController) 160 | { 161 | [_leftController removeFromParentViewController]; 162 | [_leftController.view removeFromSuperview]; 163 | } 164 | 165 | if (leftController) 166 | { 167 | [self addChildViewController:leftController]; 168 | [self.view addSubview:leftController.view]; 169 | [self.view bringSubviewToFront:_mainController.view]; 170 | } 171 | 172 | _leftController = leftController; 173 | } 174 | } 175 | 176 | - (void)setRightController:(UIViewController *)rightController 177 | { 178 | if (rightController != _rightController) 179 | { 180 | if (_rightController) 181 | { 182 | [_rightController removeFromParentViewController]; 183 | [_rightController.view removeFromSuperview]; 184 | } 185 | 186 | if (rightController) 187 | { 188 | [self addChildViewController:rightController]; 189 | [self.view addSubview:rightController.view]; 190 | [self.view bringSubviewToFront:_mainController.view]; 191 | } 192 | 193 | _rightController = rightController; 194 | } 195 | } 196 | 197 | #pragma mark - 198 | #pragma mark Public Methods 199 | 200 | - (void)toggleLeft 201 | { 202 | if (self.isOpened && self.side == BSSideLeft) 203 | { 204 | [self closeLeft]; 205 | } 206 | else 207 | { 208 | [self openLeft]; 209 | } 210 | } 211 | 212 | - (void)toggleRight 213 | { 214 | if (self.isOpened && self.side == BSSideRight) 215 | { 216 | [self closeRight]; 217 | } 218 | else 219 | { 220 | [self openRight]; 221 | } 222 | } 223 | 224 | - (void)openLeft 225 | { 226 | if (!self.isOpened || (self.isOpened && self.side == BSSideRight)) 227 | { 228 | [self prepareToShowLeftController]; 229 | [self openLeftController]; 230 | self.side = BSSideLeft; 231 | } 232 | } 233 | 234 | - (void)closeLeft 235 | { 236 | if (self.isOpened && self.side == BSSideLeft) 237 | { 238 | [self closeLeftController]; 239 | self.side = BSSideUnknown; 240 | } 241 | } 242 | 243 | - (void)openRight 244 | { 245 | if (!self.isOpened || (self.isOpened && self.side == BSSideLeft)) 246 | { 247 | [self prepareToShowRightController]; 248 | [self openRightController]; 249 | self.side = BSSideRight; 250 | } 251 | } 252 | 253 | - (void)closeRight 254 | { 255 | if (self.isOpened && self.side == BSSideRight) 256 | { 257 | [self closeRightController]; 258 | self.side = BSSideUnknown; 259 | } 260 | } 261 | 262 | #pragma mark - 263 | #pragma mark Private Methods 264 | 265 | - (void)setMainControllerPosition:(CGPoint)position animationDuration:(NSTimeInterval)animationDuration springDamping:(CGFloat)springDamping springVelocity:(CGFloat)springVelocity completion:(void(^)(void))completion 266 | { 267 | [UIView animateWithDuration:animationDuration delay:0.0f usingSpringWithDamping:springDamping initialSpringVelocity:springVelocity options:UIViewAnimationOptionCurveLinear animations:^{ 268 | CGRect rect = self.mainController.view.frame; 269 | rect.origin = position; 270 | self.mainController.view.frame = rect; 271 | } completion:^(BOOL finished) { 272 | if (finished && completion) 273 | { 274 | completion(); 275 | } 276 | }]; 277 | } 278 | 279 | - (void)openBySettingMainControllerPosition:(CGPoint)position animationDuration:(NSTimeInterval)animationDuration springDamping:(CGFloat)springDamping springVelocity:(CGFloat)springVelocity completion:(void(^)(void))completion 280 | { 281 | __weak typeof(self) weakSelf = self; 282 | [self setMainControllerPosition:position animationDuration:animationDuration springDamping:springDamping springVelocity:springVelocity completion:^{ 283 | weakSelf.opened = YES; 284 | 285 | if (completion) 286 | { 287 | completion(); 288 | } 289 | 290 | if ([weakSelf.delegate respondsToSelector:@selector(panViewController:didOpenSide:)]) 291 | { 292 | [weakSelf.delegate panViewController:weakSelf didOpenSide:weakSelf.side]; 293 | } 294 | }]; 295 | } 296 | 297 | - (void)closeBySettingMainControllerPosition:(CGPoint)position animationDuration:(NSTimeInterval)animationDuration springDamping:(CGFloat)springDamping springVelocity:(CGFloat)springVelocity completion:(void(^)(void))completion 298 | { 299 | __weak typeof(self) weakSelf = self; 300 | [self setMainControllerPosition:position animationDuration:animationDuration springDamping:springDamping springVelocity:springVelocity completion:^{ 301 | BSSide tempSide = weakSelf.side; 302 | 303 | weakSelf.opened = NO; 304 | weakSelf.side = BSSideUnknown; 305 | 306 | if (weakSelf.isStatusBarFaked) 307 | { 308 | [weakSelf hideFakeStatusBar]; 309 | } 310 | 311 | if (completion) 312 | { 313 | completion(); 314 | } 315 | 316 | if ([weakSelf.delegate respondsToSelector:@selector(panViewController:didCloseSide:)]) 317 | { 318 | [weakSelf.delegate panViewController:weakSelf didCloseSide:tempSide]; 319 | } 320 | }]; 321 | } 322 | 323 | - (void)showFakeStatusBar 324 | { 325 | CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame; 326 | CGFloat statusBarHeight = CGRectGetHeight(statusBarFrame); 327 | 328 | CGRect statusBarContainerRect = CGRectZero; 329 | statusBarContainerRect.origin.y = -statusBarHeight; 330 | statusBarContainerRect.size = CGSizeMake(CGRectGetWidth(statusBarFrame), statusBarHeight); 331 | 332 | UIView *screenshot = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO]; 333 | self.statusBarContainer = [UIView new]; 334 | self.statusBarContainer.frame = statusBarContainerRect; 335 | self.statusBarContainer.clipsToBounds = YES; 336 | self.statusBarContainer.backgroundColor = [UIColor blackColor]; 337 | [self.statusBarContainer addSubview:screenshot]; 338 | [self.mainController.view addSubview:self.statusBarContainer]; 339 | 340 | [self setStatusBarHidden:YES]; 341 | 342 | self.initialMainControllerFrame = self.mainController.view.frame; 343 | 344 | CGRect rect = self.mainController.view.frame; 345 | rect.origin.y += statusBarHeight; 346 | rect.size.height -= statusBarHeight; 347 | self.mainController.view.frame = rect; 348 | 349 | self.statusBarFaked = YES; 350 | } 351 | 352 | - (void)hideFakeStatusBar 353 | { 354 | [self.statusBarContainer removeFromSuperview]; 355 | self.statusBarContainer = nil; 356 | 357 | self.mainController.view.frame = self.initialMainControllerFrame; 358 | 359 | [self setStatusBarHidden:NO]; 360 | 361 | self.statusBarFaked = NO; 362 | } 363 | 364 | - (void)setStatusBarHidden:(BOOL)hidden 365 | { 366 | BOOL UIViewControllerBasedStatusBarAppearance = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"] boolValue]; 367 | if (UIViewControllerBasedStatusBarAppearance) 368 | { 369 | self.hideStatusBar = hidden; 370 | [self setNeedsStatusBarAppearanceUpdate]; 371 | } 372 | else 373 | { 374 | [UIApplication sharedApplication].statusBarHidden = hidden; 375 | } 376 | } 377 | 378 | #pragma mark - 379 | #pragma mark Gestures 380 | 381 | - (void)handlePanGesture:(UIGestureRecognizer *)gestureRecognizer 382 | { 383 | CGPoint location = [gestureRecognizer locationInView:self.view]; 384 | 385 | if (gestureRecognizer.state == UIGestureRecognizerStateBegan) 386 | { 387 | switch (self.side) { 388 | case BSSideLeft: 389 | [self handleLeftPanBegan:gestureRecognizer]; 390 | break; 391 | case BSSideRight: 392 | [self handleRightPanBegan:gestureRecognizer]; 393 | break; 394 | default: 395 | break; 396 | } 397 | 398 | self.panPreviousLocation = location; 399 | } 400 | else if (gestureRecognizer.state == UIGestureRecognizerStateChanged) 401 | { 402 | switch (self.side) { 403 | case BSSideLeft: 404 | [self handleLeftPanChanged:gestureRecognizer]; 405 | break; 406 | case BSSideRight: 407 | [self handleRightPanChanged:gestureRecognizer]; 408 | break; 409 | default: 410 | break; 411 | } 412 | 413 | self.panPreviousLocation = location; 414 | } 415 | else if (gestureRecognizer.state == UIGestureRecognizerStateEnded || 416 | gestureRecognizer.state == UIGestureRecognizerStateCancelled || 417 | gestureRecognizer.state == UIGestureRecognizerStateFailed) 418 | { 419 | switch (self.side) { 420 | case BSSideLeft: 421 | [self handleLeftPanStopped:gestureRecognizer]; 422 | break; 423 | case BSSideRight: 424 | [self handleRightPanStopped:gestureRecognizer]; 425 | break; 426 | default: 427 | break; 428 | } 429 | 430 | self.panPreviousLocation = CGPointZero; 431 | self.panIntention = BSPanIntentionUnknown; 432 | } 433 | } 434 | 435 | - (void)handleTapGesture:(UIGestureRecognizer *)gestureRecognizer 436 | { 437 | if (gestureRecognizer.state == UIGestureRecognizerStateEnded) 438 | { 439 | if (self.isOpened) 440 | { 441 | switch (self.side) { 442 | case BSSideLeft: 443 | if (self.leftTapToCloseEnabled) 444 | { 445 | [self closeLeftController]; 446 | } 447 | break; 448 | case BSSideRight: 449 | if (self.rightTapToCloseEnabled) 450 | { 451 | [self closeRightController]; 452 | } 453 | break; 454 | default: 455 | break; 456 | } 457 | } 458 | } 459 | } 460 | 461 | #pragma mark - 462 | #pragma mark Left Controller 463 | 464 | - (void)handleLeftPanBegan:(UIGestureRecognizer *)gestureRecognizer 465 | { 466 | [self prepareToShowLeftController]; 467 | } 468 | 469 | - (void)handleLeftPanChanged:(UIGestureRecognizer *)gestureRecognizer 470 | { 471 | CGPoint location = [gestureRecognizer locationInView:self.view]; 472 | 473 | CGPoint diffLocation = CGPointZero; 474 | diffLocation.x = location.x - self.panPreviousLocation.x; 475 | diffLocation.y = location.y - self.panPreviousLocation.y; 476 | 477 | CGRect rect = self.mainController.view.frame; 478 | CGFloat newX = rect.origin.x + diffLocation.x; 479 | newX = MAX(0.0f, MIN(newX, self.leftOpenAmount)); 480 | rect.origin.x = newX; 481 | self.mainController.view.frame = rect; 482 | 483 | self.panIntention = (diffLocation.x > 0) ? BSPanIntentionOpening : BSPanIntentionClosing; 484 | 485 | CGFloat percentage = newX / self.leftOpenAmount; 486 | CGRect leftRect = self.leftController.view.frame; 487 | leftRect.origin.x = -(self.leftOpenAmount * self.leftParallaxAmount) + (self.leftOpenAmount * self.leftParallaxAmount) * percentage; 488 | self.leftController.view.frame = leftRect; 489 | 490 | if ([self.delegate respondsToSelector:@selector(panViewController:didDragSide:toPercentage:withIntention:)]) 491 | { 492 | [self.delegate panViewController:self didDragSide:BSSideLeft toPercentage:percentage withIntention:self.panIntention]; 493 | } 494 | } 495 | 496 | - (void)handleLeftPanStopped:(UIGestureRecognizer *)gestureRecognizer 497 | { 498 | switch (self.panIntention) { 499 | case BSPanIntentionOpening: 500 | [self openLeftController]; 501 | break; 502 | case BSPanIntentionClosing: 503 | [self closeLeftController]; 504 | break; 505 | default: 506 | break; 507 | } 508 | } 509 | 510 | - (void)prepareToShowLeftController 511 | { 512 | self.leftController.view.hidden = NO; 513 | self.rightController.view.hidden = YES; 514 | 515 | [self.view bringSubviewToFront:self.leftController.view]; 516 | [self.view bringSubviewToFront:self.mainController.view]; 517 | 518 | self.mainController.view.layer.shadowColor = self.leftShadowColor.CGColor; 519 | self.mainController.view.layer.shadowOpacity = self.leftShadowOpacity; 520 | self.mainController.view.layer.shadowRadius = self.leftShadowRadius; 521 | self.mainController.view.layer.shadowOffset = self.leftShadowOffset; 522 | 523 | if (!self.isOpened && self.openingLeftMovesStatusBar && ![UIApplication sharedApplication].statusBarHidden) 524 | { 525 | [self showFakeStatusBar]; 526 | } 527 | } 528 | 529 | - (void)openLeftController 530 | { 531 | CGPoint pos = CGPointMake(self.leftOpenAmount, self.mainController.view.frame.origin.y); 532 | [self openBySettingMainControllerPosition:pos animationDuration:self.leftOpenAnimationDuration springDamping:self.leftOpenSpringDamping springVelocity:self.leftOpenSpringVelocity completion:nil]; 533 | 534 | [self animateLeftParallaxIn]; 535 | } 536 | 537 | - (void)closeLeftController 538 | { 539 | CGPoint pos = CGPointMake(0.0f, self.mainController.view.frame.origin.y); 540 | [self closeBySettingMainControllerPosition:pos animationDuration:self.leftCloseAnimationDuration springDamping:self.leftCloseSpringDamping springVelocity:self.leftCloseSpringVelocity completion:nil]; 541 | 542 | [self animateLeftParallaxOut]; 543 | } 544 | 545 | - (void)animateLeftParallaxIn 546 | { 547 | [UIView animateWithDuration:self.leftOpenAnimationDuration delay:0.0f usingSpringWithDamping:self.leftOpenSpringDamping initialSpringVelocity:self.leftOpenSpringVelocity options:UIViewAnimationOptionCurveLinear animations:^{ 548 | CGRect rect = self.leftController.view.frame; 549 | rect.origin.x = 0.0f; 550 | self.leftController.view.frame = rect; 551 | } completion:nil]; 552 | } 553 | 554 | - (void)animateLeftParallaxOut 555 | { 556 | [UIView animateWithDuration:self.leftCloseAnimationDuration delay:0.0f usingSpringWithDamping:self.leftCloseSpringDamping initialSpringVelocity:self.leftCloseSpringVelocity options:UIViewAnimationOptionCurveLinear animations:^{ 557 | CGRect rect = self.leftController.view.frame; 558 | rect.origin.x = -self.leftOpenAmount * self.leftParallaxAmount; 559 | self.leftController.view.frame = rect; 560 | } completion:nil]; 561 | } 562 | 563 | - (BOOL)isPointInLeftOpenRect:(CGPoint)pos 564 | { 565 | CGRect rect = CGRectZero; 566 | rect.size = CGSizeMake(self.leftPanSize, CGRectGetHeight(self.view.bounds)); 567 | return CGRectContainsPoint(rect, pos); 568 | } 569 | 570 | - (BOOL)isPointInLeftCloseRect:(CGPoint)pos 571 | { 572 | return CGRectContainsPoint(self.mainController.view.frame, pos); 573 | } 574 | 575 | #pragma mark - 576 | #pragma mark Right Controller 577 | 578 | - (void)handleRightPanBegan:(UIGestureRecognizer *)gestureRecognizer 579 | { 580 | [self prepareToShowRightController]; 581 | } 582 | 583 | - (void)handleRightPanChanged:(UIGestureRecognizer *)gestureRecognizer 584 | { 585 | CGPoint location = [gestureRecognizer locationInView:self.view]; 586 | 587 | CGPoint diffLocation = CGPointZero; 588 | diffLocation.x = location.x - self.panPreviousLocation.x; 589 | diffLocation.y = location.y - self.panPreviousLocation.y; 590 | 591 | CGRect rect = self.mainController.view.frame; 592 | CGFloat newX = rect.origin.x + diffLocation.x; 593 | newX = MIN(0.0f, MAX(newX, -self.rightOpenAmount)); 594 | rect.origin.x = newX; 595 | self.mainController.view.frame = rect; 596 | 597 | self.panIntention = (diffLocation.x < 0) ? BSPanIntentionOpening : BSPanIntentionClosing; 598 | 599 | CGFloat percentage = fabsf(newX / self.rightOpenAmount); 600 | CGRect rightRect = self.rightController.view.frame; 601 | rightRect.origin.x = (self.rightOpenAmount * self.rightParallaxAmount) - (self.rightOpenAmount * self.rightParallaxAmount) * percentage; 602 | self.rightController.view.frame = rightRect; 603 | 604 | if ([self.delegate respondsToSelector:@selector(panViewController:didDragSide:toPercentage:withIntention:)]) 605 | { 606 | [self.delegate panViewController:self didDragSide:BSSideRight toPercentage:percentage withIntention:self.panIntention]; 607 | } 608 | } 609 | 610 | - (void)handleRightPanStopped:(UIGestureRecognizer *)gestureRecognizer 611 | { 612 | switch (self.panIntention) { 613 | case BSPanIntentionOpening: 614 | [self openRightController]; 615 | break; 616 | case BSPanIntentionClosing: 617 | [self closeRightController]; 618 | break; 619 | default: 620 | break; 621 | } 622 | } 623 | 624 | - (void)prepareToShowRightController 625 | { 626 | self.leftController.view.hidden = YES; 627 | self.rightController.view.hidden = NO; 628 | 629 | [self.view bringSubviewToFront:self.rightController.view]; 630 | [self.view bringSubviewToFront:self.mainController.view]; 631 | 632 | self.mainController.view.layer.shadowColor = self.rightShadowColor.CGColor; 633 | self.mainController.view.layer.shadowOpacity = self.rightShadowOpacity; 634 | self.mainController.view.layer.shadowRadius = self.rightShadowRadius; 635 | self.mainController.view.layer.shadowOffset = self.rightShadowOffset; 636 | 637 | if (!self.isOpened && self.openingRightMovesStatusBar && ![UIApplication sharedApplication].statusBarHidden) 638 | { 639 | [self showFakeStatusBar]; 640 | } 641 | } 642 | 643 | - (void)openRightController 644 | { 645 | CGPoint pos = CGPointMake(-self.rightOpenAmount, self.mainController.view.frame.origin.y); 646 | [self openBySettingMainControllerPosition:pos animationDuration:self.rightOpenAnimationDuration springDamping:self.rightOpenSpringDamping springVelocity:self.rightOpenSpringVelocity completion:nil]; 647 | 648 | [self animateRightParallaxIn]; 649 | } 650 | 651 | - (void)closeRightController 652 | { 653 | CGPoint pos = CGPointMake(0.0f, self.mainController.view.frame.origin.y); 654 | [self closeBySettingMainControllerPosition:pos animationDuration:self.rightCloseAnimationDuration springDamping:self.rightCloseSpringDamping springVelocity:self.rightCloseSpringVelocity completion:nil]; 655 | 656 | [self animateRightParallaxOut]; 657 | } 658 | 659 | - (void)animateRightParallaxIn 660 | { 661 | [UIView animateWithDuration:self.rightOpenAnimationDuration delay:0.0f usingSpringWithDamping:self.rightOpenSpringDamping initialSpringVelocity:self.rightOpenSpringVelocity options:UIViewAnimationOptionCurveLinear animations:^{ 662 | CGRect rect = self.rightController.view.frame; 663 | rect.origin.x = 0.0f; 664 | self.rightController.view.frame = rect; 665 | } completion:nil]; 666 | } 667 | 668 | - (void)animateRightParallaxOut 669 | { 670 | [UIView animateWithDuration:self.rightCloseAnimationDuration delay:0.0f usingSpringWithDamping:self.rightCloseSpringDamping initialSpringVelocity:self.rightCloseSpringVelocity options:UIViewAnimationOptionCurveLinear animations:^{ 671 | CGRect rect = self.rightController.view.frame; 672 | rect.origin.x = self.rightOpenAmount * self.rightParallaxAmount; 673 | self.rightController.view.frame = rect; 674 | } completion:nil]; 675 | } 676 | 677 | - (BOOL)isPointInRightOpenRect:(CGPoint)pos 678 | { 679 | CGRect rect = CGRectZero; 680 | rect.origin = CGPointMake(CGRectGetWidth(self.mainController.view.frame) - self.rightPanSize, 0.0f); 681 | rect.size = CGSizeMake(self.rightPanSize, CGRectGetHeight(self.view.bounds)); 682 | return CGRectContainsPoint(rect, pos); 683 | } 684 | 685 | - (BOOL)isPointInRightCloseRect:(CGPoint)pos 686 | { 687 | return CGRectContainsPoint(self.mainController.view.frame, pos); 688 | } 689 | 690 | #pragma mark - 691 | #pragma mark Gesture Recognizer Delegate 692 | 693 | - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 694 | { 695 | CGPoint location = [gestureRecognizer locationInView:self.view]; 696 | 697 | if (self.isLeftPanEnabled && !self.isOpened && [self isPointInLeftOpenRect:location]) 698 | { 699 | // Open left side 700 | self.side = BSSideLeft; 701 | return YES; 702 | } 703 | else if (self.isLeftPanEnabled && self.isOpened && self.side == BSSideLeft && [self isPointInLeftCloseRect:location]) 704 | { 705 | // Close left side 706 | return YES; 707 | } 708 | else if (self.isRightPanEnabled && !self.isOpened && [self isPointInRightOpenRect:location]) 709 | { 710 | // Open right side 711 | self.side = BSSideRight; 712 | return YES; 713 | } 714 | else if (self.isRightPanEnabled && self.isOpened && self.side == BSSideRight && [self isPointInRightCloseRect:location]) 715 | { 716 | // Close right side 717 | return YES; 718 | } 719 | 720 | return NO; 721 | } 722 | 723 | @end 724 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 729B7B341838CC31009C50E3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 729B7B331838CC31009C50E3 /* Foundation.framework */; }; 11 | 729B7B361838CC31009C50E3 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 729B7B351838CC31009C50E3 /* CoreGraphics.framework */; }; 12 | 729B7B381838CC31009C50E3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 729B7B371838CC31009C50E3 /* UIKit.framework */; }; 13 | 729B7B3E1838CC31009C50E3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 729B7B3C1838CC31009C50E3 /* InfoPlist.strings */; }; 14 | 729B7B401838CC31009C50E3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 729B7B3F1838CC31009C50E3 /* main.m */; }; 15 | 729B7B461838CC31009C50E3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 729B7B451838CC31009C50E3 /* Images.xcassets */; }; 16 | 729B7B4D1838CC31009C50E3 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 729B7B4C1838CC31009C50E3 /* XCTest.framework */; }; 17 | 729B7B4E1838CC31009C50E3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 729B7B331838CC31009C50E3 /* Foundation.framework */; }; 18 | 729B7B4F1838CC31009C50E3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 729B7B371838CC31009C50E3 /* UIKit.framework */; }; 19 | 729B7B571838CC31009C50E3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 729B7B551838CC31009C50E3 /* InfoPlist.strings */; }; 20 | 729B7B591838CC31009C50E3 /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 729B7B581838CC31009C50E3 /* ExampleTests.m */; }; 21 | 729B7B661838CC71009C50E3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 729B7B651838CC71009C50E3 /* AppDelegate.m */; }; 22 | 729B7B6A1838CCA1009C50E3 /* BSPanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 729B7B691838CCA1009C50E3 /* BSPanViewController.m */; }; 23 | 729B7B6D1838CD0D009C50E3 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 729B7B6C1838CD0D009C50E3 /* MainViewController.m */; }; 24 | 729B7B701838CD2C009C50E3 /* LeftViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 729B7B6F1838CD2C009C50E3 /* LeftViewController.m */; }; 25 | 729B7B731838FD1A009C50E3 /* RightViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 729B7B721838FD1A009C50E3 /* RightViewController.m */; }; 26 | 729B7B7618390268009C50E3 /* SideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 729B7B7518390268009C50E3 /* SideViewController.m */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 729B7B501838CC31009C50E3 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 729B7B281838CC31009C50E3 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 729B7B2F1838CC31009C50E3; 35 | remoteInfo = Example; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 729B7B301838CC31009C50E3 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 729B7B331838CC31009C50E3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 42 | 729B7B351838CC31009C50E3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 43 | 729B7B371838CC31009C50E3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 44 | 729B7B3B1838CC31009C50E3 /* Example-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Example-Info.plist"; sourceTree = ""; }; 45 | 729B7B3D1838CC31009C50E3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 46 | 729B7B3F1838CC31009C50E3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 729B7B411838CC31009C50E3 /* Example-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Example-Prefix.pch"; sourceTree = ""; }; 48 | 729B7B451838CC31009C50E3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 49 | 729B7B4B1838CC31009C50E3 /* ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 729B7B4C1838CC31009C50E3 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 51 | 729B7B541838CC31009C50E3 /* ExampleTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ExampleTests-Info.plist"; sourceTree = ""; }; 52 | 729B7B561838CC31009C50E3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 53 | 729B7B581838CC31009C50E3 /* ExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleTests.m; sourceTree = ""; }; 54 | 729B7B641838CC71009C50E3 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 55 | 729B7B651838CC71009C50E3 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 56 | 729B7B681838CCA1009C50E3 /* BSPanViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSPanViewController.h; sourceTree = ""; }; 57 | 729B7B691838CCA1009C50E3 /* BSPanViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSPanViewController.m; sourceTree = ""; }; 58 | 729B7B6B1838CD0D009C50E3 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; 59 | 729B7B6C1838CD0D009C50E3 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; 60 | 729B7B6E1838CD2C009C50E3 /* LeftViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LeftViewController.h; sourceTree = ""; }; 61 | 729B7B6F1838CD2C009C50E3 /* LeftViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LeftViewController.m; sourceTree = ""; }; 62 | 729B7B711838FD1A009C50E3 /* RightViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RightViewController.h; sourceTree = ""; }; 63 | 729B7B721838FD1A009C50E3 /* RightViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RightViewController.m; sourceTree = ""; }; 64 | 729B7B7418390268009C50E3 /* SideViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SideViewController.h; sourceTree = ""; }; 65 | 729B7B7518390268009C50E3 /* SideViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SideViewController.m; sourceTree = ""; }; 66 | /* End PBXFileReference section */ 67 | 68 | /* Begin PBXFrameworksBuildPhase section */ 69 | 729B7B2D1838CC31009C50E3 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | 729B7B361838CC31009C50E3 /* CoreGraphics.framework in Frameworks */, 74 | 729B7B381838CC31009C50E3 /* UIKit.framework in Frameworks */, 75 | 729B7B341838CC31009C50E3 /* Foundation.framework in Frameworks */, 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | 729B7B481838CC31009C50E3 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | 729B7B4D1838CC31009C50E3 /* XCTest.framework in Frameworks */, 84 | 729B7B4F1838CC31009C50E3 /* UIKit.framework in Frameworks */, 85 | 729B7B4E1838CC31009C50E3 /* Foundation.framework in Frameworks */, 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | /* End PBXFrameworksBuildPhase section */ 90 | 91 | /* Begin PBXGroup section */ 92 | 729B7B271838CC31009C50E3 = { 93 | isa = PBXGroup; 94 | children = ( 95 | 729B7B391838CC31009C50E3 /* Example */, 96 | 729B7B521838CC31009C50E3 /* ExampleTests */, 97 | 729B7B321838CC31009C50E3 /* Frameworks */, 98 | 729B7B311838CC31009C50E3 /* Products */, 99 | ); 100 | sourceTree = ""; 101 | }; 102 | 729B7B311838CC31009C50E3 /* Products */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 729B7B301838CC31009C50E3 /* Example.app */, 106 | 729B7B4B1838CC31009C50E3 /* ExampleTests.xctest */, 107 | ); 108 | name = Products; 109 | sourceTree = ""; 110 | }; 111 | 729B7B321838CC31009C50E3 /* Frameworks */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 729B7B331838CC31009C50E3 /* Foundation.framework */, 115 | 729B7B351838CC31009C50E3 /* CoreGraphics.framework */, 116 | 729B7B371838CC31009C50E3 /* UIKit.framework */, 117 | 729B7B4C1838CC31009C50E3 /* XCTest.framework */, 118 | ); 119 | name = Frameworks; 120 | sourceTree = ""; 121 | }; 122 | 729B7B391838CC31009C50E3 /* Example */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 729B7B451838CC31009C50E3 /* Images.xcassets */, 126 | 729B7B621838CC71009C50E3 /* Source */, 127 | 729B7B3A1838CC31009C50E3 /* Supporting Files */, 128 | ); 129 | path = Example; 130 | sourceTree = ""; 131 | }; 132 | 729B7B3A1838CC31009C50E3 /* Supporting Files */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 729B7B3B1838CC31009C50E3 /* Example-Info.plist */, 136 | 729B7B3C1838CC31009C50E3 /* InfoPlist.strings */, 137 | 729B7B3F1838CC31009C50E3 /* main.m */, 138 | 729B7B411838CC31009C50E3 /* Example-Prefix.pch */, 139 | ); 140 | name = "Supporting Files"; 141 | sourceTree = ""; 142 | }; 143 | 729B7B521838CC31009C50E3 /* ExampleTests */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 729B7B581838CC31009C50E3 /* ExampleTests.m */, 147 | 729B7B531838CC31009C50E3 /* Supporting Files */, 148 | ); 149 | path = ExampleTests; 150 | sourceTree = ""; 151 | }; 152 | 729B7B531838CC31009C50E3 /* Supporting Files */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 729B7B541838CC31009C50E3 /* ExampleTests-Info.plist */, 156 | 729B7B551838CC31009C50E3 /* InfoPlist.strings */, 157 | ); 158 | name = "Supporting Files"; 159 | sourceTree = ""; 160 | }; 161 | 729B7B621838CC71009C50E3 /* Source */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 729B7B671838CC80009C50E3 /* BSPanViewController */, 165 | 729B7B631838CC71009C50E3 /* Controllers */, 166 | ); 167 | path = Source; 168 | sourceTree = ""; 169 | }; 170 | 729B7B631838CC71009C50E3 /* Controllers */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | 729B7B641838CC71009C50E3 /* AppDelegate.h */, 174 | 729B7B651838CC71009C50E3 /* AppDelegate.m */, 175 | 729B7B6B1838CD0D009C50E3 /* MainViewController.h */, 176 | 729B7B6C1838CD0D009C50E3 /* MainViewController.m */, 177 | 729B7B7418390268009C50E3 /* SideViewController.h */, 178 | 729B7B7518390268009C50E3 /* SideViewController.m */, 179 | 729B7B6E1838CD2C009C50E3 /* LeftViewController.h */, 180 | 729B7B6F1838CD2C009C50E3 /* LeftViewController.m */, 181 | 729B7B711838FD1A009C50E3 /* RightViewController.h */, 182 | 729B7B721838FD1A009C50E3 /* RightViewController.m */, 183 | ); 184 | path = Controllers; 185 | sourceTree = ""; 186 | }; 187 | 729B7B671838CC80009C50E3 /* BSPanViewController */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 729B7B681838CCA1009C50E3 /* BSPanViewController.h */, 191 | 729B7B691838CCA1009C50E3 /* BSPanViewController.m */, 192 | ); 193 | name = BSPanViewController; 194 | path = ../../../BSPanViewController; 195 | sourceTree = ""; 196 | }; 197 | /* End PBXGroup section */ 198 | 199 | /* Begin PBXNativeTarget section */ 200 | 729B7B2F1838CC31009C50E3 /* Example */ = { 201 | isa = PBXNativeTarget; 202 | buildConfigurationList = 729B7B5C1838CC31009C50E3 /* Build configuration list for PBXNativeTarget "Example" */; 203 | buildPhases = ( 204 | 729B7B2C1838CC31009C50E3 /* Sources */, 205 | 729B7B2D1838CC31009C50E3 /* Frameworks */, 206 | 729B7B2E1838CC31009C50E3 /* Resources */, 207 | ); 208 | buildRules = ( 209 | ); 210 | dependencies = ( 211 | ); 212 | name = Example; 213 | productName = Example; 214 | productReference = 729B7B301838CC31009C50E3 /* Example.app */; 215 | productType = "com.apple.product-type.application"; 216 | }; 217 | 729B7B4A1838CC31009C50E3 /* ExampleTests */ = { 218 | isa = PBXNativeTarget; 219 | buildConfigurationList = 729B7B5F1838CC31009C50E3 /* Build configuration list for PBXNativeTarget "ExampleTests" */; 220 | buildPhases = ( 221 | 729B7B471838CC31009C50E3 /* Sources */, 222 | 729B7B481838CC31009C50E3 /* Frameworks */, 223 | 729B7B491838CC31009C50E3 /* Resources */, 224 | ); 225 | buildRules = ( 226 | ); 227 | dependencies = ( 228 | 729B7B511838CC31009C50E3 /* PBXTargetDependency */, 229 | ); 230 | name = ExampleTests; 231 | productName = ExampleTests; 232 | productReference = 729B7B4B1838CC31009C50E3 /* ExampleTests.xctest */; 233 | productType = "com.apple.product-type.bundle.unit-test"; 234 | }; 235 | /* End PBXNativeTarget section */ 236 | 237 | /* Begin PBXProject section */ 238 | 729B7B281838CC31009C50E3 /* Project object */ = { 239 | isa = PBXProject; 240 | attributes = { 241 | LastUpgradeCheck = 0500; 242 | ORGANIZATIONNAME = intuitaps; 243 | TargetAttributes = { 244 | 729B7B4A1838CC31009C50E3 = { 245 | TestTargetID = 729B7B2F1838CC31009C50E3; 246 | }; 247 | }; 248 | }; 249 | buildConfigurationList = 729B7B2B1838CC31009C50E3 /* Build configuration list for PBXProject "Example" */; 250 | compatibilityVersion = "Xcode 3.2"; 251 | developmentRegion = English; 252 | hasScannedForEncodings = 0; 253 | knownRegions = ( 254 | en, 255 | ); 256 | mainGroup = 729B7B271838CC31009C50E3; 257 | productRefGroup = 729B7B311838CC31009C50E3 /* Products */; 258 | projectDirPath = ""; 259 | projectRoot = ""; 260 | targets = ( 261 | 729B7B2F1838CC31009C50E3 /* Example */, 262 | 729B7B4A1838CC31009C50E3 /* ExampleTests */, 263 | ); 264 | }; 265 | /* End PBXProject section */ 266 | 267 | /* Begin PBXResourcesBuildPhase section */ 268 | 729B7B2E1838CC31009C50E3 /* Resources */ = { 269 | isa = PBXResourcesBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | 729B7B3E1838CC31009C50E3 /* InfoPlist.strings in Resources */, 273 | 729B7B461838CC31009C50E3 /* Images.xcassets in Resources */, 274 | ); 275 | runOnlyForDeploymentPostprocessing = 0; 276 | }; 277 | 729B7B491838CC31009C50E3 /* Resources */ = { 278 | isa = PBXResourcesBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | 729B7B571838CC31009C50E3 /* InfoPlist.strings in Resources */, 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | /* End PBXResourcesBuildPhase section */ 286 | 287 | /* Begin PBXSourcesBuildPhase section */ 288 | 729B7B2C1838CC31009C50E3 /* Sources */ = { 289 | isa = PBXSourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | 729B7B661838CC71009C50E3 /* AppDelegate.m in Sources */, 293 | 729B7B701838CD2C009C50E3 /* LeftViewController.m in Sources */, 294 | 729B7B6A1838CCA1009C50E3 /* BSPanViewController.m in Sources */, 295 | 729B7B401838CC31009C50E3 /* main.m in Sources */, 296 | 729B7B6D1838CD0D009C50E3 /* MainViewController.m in Sources */, 297 | 729B7B731838FD1A009C50E3 /* RightViewController.m in Sources */, 298 | 729B7B7618390268009C50E3 /* SideViewController.m in Sources */, 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | 729B7B471838CC31009C50E3 /* Sources */ = { 303 | isa = PBXSourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | 729B7B591838CC31009C50E3 /* ExampleTests.m in Sources */, 307 | ); 308 | runOnlyForDeploymentPostprocessing = 0; 309 | }; 310 | /* End PBXSourcesBuildPhase section */ 311 | 312 | /* Begin PBXTargetDependency section */ 313 | 729B7B511838CC31009C50E3 /* PBXTargetDependency */ = { 314 | isa = PBXTargetDependency; 315 | target = 729B7B2F1838CC31009C50E3 /* Example */; 316 | targetProxy = 729B7B501838CC31009C50E3 /* PBXContainerItemProxy */; 317 | }; 318 | /* End PBXTargetDependency section */ 319 | 320 | /* Begin PBXVariantGroup section */ 321 | 729B7B3C1838CC31009C50E3 /* InfoPlist.strings */ = { 322 | isa = PBXVariantGroup; 323 | children = ( 324 | 729B7B3D1838CC31009C50E3 /* en */, 325 | ); 326 | name = InfoPlist.strings; 327 | sourceTree = ""; 328 | }; 329 | 729B7B551838CC31009C50E3 /* InfoPlist.strings */ = { 330 | isa = PBXVariantGroup; 331 | children = ( 332 | 729B7B561838CC31009C50E3 /* en */, 333 | ); 334 | name = InfoPlist.strings; 335 | sourceTree = ""; 336 | }; 337 | /* End PBXVariantGroup section */ 338 | 339 | /* Begin XCBuildConfiguration section */ 340 | 729B7B5A1838CC31009C50E3 /* Debug */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | ALWAYS_SEARCH_USER_PATHS = NO; 344 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 345 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 346 | CLANG_CXX_LIBRARY = "libc++"; 347 | CLANG_ENABLE_MODULES = YES; 348 | CLANG_ENABLE_OBJC_ARC = YES; 349 | CLANG_WARN_BOOL_CONVERSION = YES; 350 | CLANG_WARN_CONSTANT_CONVERSION = YES; 351 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 352 | CLANG_WARN_EMPTY_BODY = YES; 353 | CLANG_WARN_ENUM_CONVERSION = YES; 354 | CLANG_WARN_INT_CONVERSION = YES; 355 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 356 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 357 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 358 | COPY_PHASE_STRIP = NO; 359 | GCC_C_LANGUAGE_STANDARD = gnu99; 360 | GCC_DYNAMIC_NO_PIC = NO; 361 | GCC_OPTIMIZATION_LEVEL = 0; 362 | GCC_PREPROCESSOR_DEFINITIONS = ( 363 | "DEBUG=1", 364 | "$(inherited)", 365 | ); 366 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 367 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 368 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 369 | GCC_WARN_UNDECLARED_SELECTOR = YES; 370 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 371 | GCC_WARN_UNUSED_FUNCTION = YES; 372 | GCC_WARN_UNUSED_VARIABLE = YES; 373 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 374 | ONLY_ACTIVE_ARCH = YES; 375 | SDKROOT = iphoneos; 376 | }; 377 | name = Debug; 378 | }; 379 | 729B7B5B1838CC31009C50E3 /* Release */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | ALWAYS_SEARCH_USER_PATHS = NO; 383 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 384 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 385 | CLANG_CXX_LIBRARY = "libc++"; 386 | CLANG_ENABLE_MODULES = YES; 387 | CLANG_ENABLE_OBJC_ARC = YES; 388 | CLANG_WARN_BOOL_CONVERSION = YES; 389 | CLANG_WARN_CONSTANT_CONVERSION = YES; 390 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 391 | CLANG_WARN_EMPTY_BODY = YES; 392 | CLANG_WARN_ENUM_CONVERSION = YES; 393 | CLANG_WARN_INT_CONVERSION = YES; 394 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 395 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 396 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 397 | COPY_PHASE_STRIP = YES; 398 | ENABLE_NS_ASSERTIONS = NO; 399 | GCC_C_LANGUAGE_STANDARD = gnu99; 400 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 401 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 402 | GCC_WARN_UNDECLARED_SELECTOR = YES; 403 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 404 | GCC_WARN_UNUSED_FUNCTION = YES; 405 | GCC_WARN_UNUSED_VARIABLE = YES; 406 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 407 | SDKROOT = iphoneos; 408 | VALIDATE_PRODUCT = YES; 409 | }; 410 | name = Release; 411 | }; 412 | 729B7B5D1838CC31009C50E3 /* Debug */ = { 413 | isa = XCBuildConfiguration; 414 | buildSettings = { 415 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 416 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 417 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 418 | GCC_PREFIX_HEADER = "Example/Example-Prefix.pch"; 419 | INFOPLIST_FILE = "Example/Example-Info.plist"; 420 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 421 | PRODUCT_NAME = "$(TARGET_NAME)"; 422 | WRAPPER_EXTENSION = app; 423 | }; 424 | name = Debug; 425 | }; 426 | 729B7B5E1838CC31009C50E3 /* Release */ = { 427 | isa = XCBuildConfiguration; 428 | buildSettings = { 429 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 430 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 431 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 432 | GCC_PREFIX_HEADER = "Example/Example-Prefix.pch"; 433 | INFOPLIST_FILE = "Example/Example-Info.plist"; 434 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 435 | PRODUCT_NAME = "$(TARGET_NAME)"; 436 | WRAPPER_EXTENSION = app; 437 | }; 438 | name = Release; 439 | }; 440 | 729B7B601838CC31009C50E3 /* Debug */ = { 441 | isa = XCBuildConfiguration; 442 | buildSettings = { 443 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 444 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Example.app/Example"; 445 | FRAMEWORK_SEARCH_PATHS = ( 446 | "$(SDKROOT)/Developer/Library/Frameworks", 447 | "$(inherited)", 448 | "$(DEVELOPER_FRAMEWORKS_DIR)", 449 | ); 450 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 451 | GCC_PREFIX_HEADER = "Example/Example-Prefix.pch"; 452 | GCC_PREPROCESSOR_DEFINITIONS = ( 453 | "DEBUG=1", 454 | "$(inherited)", 455 | ); 456 | INFOPLIST_FILE = "ExampleTests/ExampleTests-Info.plist"; 457 | PRODUCT_NAME = "$(TARGET_NAME)"; 458 | TEST_HOST = "$(BUNDLE_LOADER)"; 459 | WRAPPER_EXTENSION = xctest; 460 | }; 461 | name = Debug; 462 | }; 463 | 729B7B611838CC31009C50E3 /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 467 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Example.app/Example"; 468 | FRAMEWORK_SEARCH_PATHS = ( 469 | "$(SDKROOT)/Developer/Library/Frameworks", 470 | "$(inherited)", 471 | "$(DEVELOPER_FRAMEWORKS_DIR)", 472 | ); 473 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 474 | GCC_PREFIX_HEADER = "Example/Example-Prefix.pch"; 475 | INFOPLIST_FILE = "ExampleTests/ExampleTests-Info.plist"; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | TEST_HOST = "$(BUNDLE_LOADER)"; 478 | WRAPPER_EXTENSION = xctest; 479 | }; 480 | name = Release; 481 | }; 482 | /* End XCBuildConfiguration section */ 483 | 484 | /* Begin XCConfigurationList section */ 485 | 729B7B2B1838CC31009C50E3 /* Build configuration list for PBXProject "Example" */ = { 486 | isa = XCConfigurationList; 487 | buildConfigurations = ( 488 | 729B7B5A1838CC31009C50E3 /* Debug */, 489 | 729B7B5B1838CC31009C50E3 /* Release */, 490 | ); 491 | defaultConfigurationIsVisible = 0; 492 | defaultConfigurationName = Release; 493 | }; 494 | 729B7B5C1838CC31009C50E3 /* Build configuration list for PBXNativeTarget "Example" */ = { 495 | isa = XCConfigurationList; 496 | buildConfigurations = ( 497 | 729B7B5D1838CC31009C50E3 /* Debug */, 498 | 729B7B5E1838CC31009C50E3 /* Release */, 499 | ); 500 | defaultConfigurationIsVisible = 0; 501 | defaultConfigurationName = Release; 502 | }; 503 | 729B7B5F1838CC31009C50E3 /* Build configuration list for PBXNativeTarget "ExampleTests" */ = { 504 | isa = XCConfigurationList; 505 | buildConfigurations = ( 506 | 729B7B601838CC31009C50E3 /* Debug */, 507 | 729B7B611838CC31009C50E3 /* Release */, 508 | ); 509 | defaultConfigurationIsVisible = 0; 510 | defaultConfigurationName = Release; 511 | }; 512 | /* End XCConfigurationList section */ 513 | }; 514 | rootObject = 729B7B281838CC31009C50E3 /* Project object */; 515 | } 516 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/xcshareddata/Example.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | BD9F32F2-E7E8-4EBD-A5B0-775736AA7EEF 9 | IDESourceControlProjectName 10 | Example 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 21EEC358-2AD1-4508-8959-DFF440C62A12 14 | ssh://github.com/simonbs/BSPanViewController.git 15 | 16 | IDESourceControlProjectPath 17 | Example/Example.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 21EEC358-2AD1-4508-8959-DFF440C62A12 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | ssh://github.com/simonbs/BSPanViewController.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 21EEC358-2AD1-4508-8959-DFF440C62A12 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 21EEC358-2AD1-4508-8959-DFF440C62A12 36 | IDESourceControlWCCName 37 | BSPanViewController 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/xcuserdata/simonbs.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simonbs/BSPanViewController/49161ca29b243790673a3b4deaf0922530db6ec6/Example/Example.xcodeproj/project.xcworkspace/xcuserdata/simonbs.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/xcuserdata/simonbs.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/xcuserdata/simonbs.xcuserdatad/xcschemes/Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/xcuserdata/simonbs.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Example.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 729B7B2F1838CC31009C50E3 16 | 17 | primary 18 | 19 | 20 | 729B7B4A1838CC31009C50E3 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/Example/Example-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | dk.intuitaps.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UIViewControllerBasedStatusBarAppearance 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Example/Example/Example-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/LeftBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "LeftBackground.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/LeftBackground.imageset/LeftBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simonbs/BSPanViewController/49161ca29b243790673a3b4deaf0922530db6ec6/Example/Example/Images.xcassets/LeftBackground.imageset/LeftBackground.png -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/Menu.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "Menu.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "Menu@2x.png" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/Menu.imageset/Menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simonbs/BSPanViewController/49161ca29b243790673a3b4deaf0922530db6ec6/Example/Example/Images.xcassets/Menu.imageset/Menu.png -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/Menu.imageset/Menu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simonbs/BSPanViewController/49161ca29b243790673a3b4deaf0922530db6ec6/Example/Example/Images.xcassets/Menu.imageset/Menu@2x.png -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/RightBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "RightBackground.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/RightBackground.imageset/RightBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simonbs/BSPanViewController/49161ca29b243790673a3b4deaf0922530db6ec6/Example/Example/Images.xcassets/RightBackground.imageset/RightBackground.png -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define TheAppDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate]) 12 | 13 | @class BSPanViewController; 14 | 15 | @interface AppDelegate : UIResponder 16 | 17 | @property (nonatomic, strong) UIWindow *window; 18 | @property (nonatomic, readonly) BSPanViewController *panController; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "BSPanViewController.h" 11 | #import "MainViewController.h" 12 | #import "LeftViewController.h" 13 | #import "RightViewController.h" 14 | 15 | @implementation AppDelegate 16 | 17 | #pragma mark - 18 | #pragma mark Lifecycle 19 | 20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 21 | { 22 | [self applyAppearance]; 23 | 24 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:[MainViewController new]]; 25 | 26 | _panController = [BSPanViewController new]; 27 | _panController.leftPanEnabled = YES; 28 | _panController.rightPanEnabled = YES; 29 | _panController.mainController = navigationController; 30 | _panController.leftController = [LeftViewController new]; 31 | _panController.rightController = [RightViewController new]; 32 | _panController.openingLeftMovesStatusBar = YES; 33 | _panController.openingRightMovesStatusBar = NO; 34 | 35 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 36 | self.window.backgroundColor = [UIColor whiteColor]; 37 | self.window.rootViewController = _panController; 38 | [self.window makeKeyAndVisible]; 39 | 40 | return YES; 41 | } 42 | 43 | - (void)applicationWillResignActive:(UIApplication *)application 44 | { 45 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 46 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 47 | } 48 | 49 | - (void)applicationDidEnterBackground:(UIApplication *)application 50 | { 51 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 52 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 53 | } 54 | 55 | - (void)applicationWillEnterForeground:(UIApplication *)application 56 | { 57 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 58 | } 59 | 60 | - (void)applicationDidBecomeActive:(UIApplication *)application 61 | { 62 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 63 | } 64 | 65 | - (void)applicationWillTerminate:(UIApplication *)application 66 | { 67 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 68 | } 69 | 70 | - (void)dealloc 71 | { 72 | _panController = nil; 73 | } 74 | 75 | #pragma mark - 76 | #pragma mark Private Methods 77 | 78 | - (void)applyAppearance 79 | { 80 | UIColor *barTintColor = [UIColor colorWithRed:0.413 green:0.502 blue:0.539 alpha:1.000]; 81 | UIColor *tintColor = [UIColor whiteColor]; 82 | UIColor *navigationBarTextColor = [UIColor whiteColor]; 83 | 84 | [[UINavigationBar appearance] setBarTintColor:barTintColor]; 85 | [[UINavigationBar appearance] setTintColor:tintColor]; 86 | [[UINavigationBar appearance] setTitleTextAttributes:@{ NSForegroundColorAttributeName : navigationBarTextColor }]; 87 | 88 | [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/LeftViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LeftViewController.h 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import "SideViewController.h" 10 | 11 | @interface LeftViewController : SideViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/LeftViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LeftViewController.m 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import "LeftViewController.h" 10 | 11 | @interface LeftViewController () 12 | @end 13 | 14 | @implementation LeftViewController 15 | 16 | #pragma mark - 17 | #pragma mark Lifecycle 18 | 19 | - (void)viewDidLoad 20 | { 21 | [super viewDidLoad]; 22 | 23 | self.backgroundImageView.image = [UIImage imageNamed:@"LeftBackground"]; 24 | 25 | UITableView *tableView = [UITableView new]; 26 | tableView.translatesAutoresizingMaskIntoConstraints = NO; 27 | tableView.dataSource = self; 28 | tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 29 | tableView.backgroundColor = [UIColor clearColor]; 30 | [self.view addSubview:tableView]; 31 | 32 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[tableView]|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(tableView)]]; 33 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(tableView)]]; 34 | } 35 | 36 | #pragma mark - 37 | #pragma mark Table View Data Source 38 | 39 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 40 | { 41 | static NSString *cellIdentifier = @"Cell"; 42 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 43 | if (!cell) 44 | { 45 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 46 | cell.backgroundColor = [UIColor clearColor]; 47 | cell.textLabel.textColor = [UIColor whiteColor]; 48 | cell.textLabel.font = [UIFont boldSystemFontOfSize:17.0f]; 49 | cell.textLabel.shadowColor = [UIColor blackColor]; 50 | cell.textLabel.shadowOffset = CGSizeMake(0.0f, 1.0f); 51 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 52 | } 53 | 54 | cell.textLabel.text = @"BSPanViewController"; 55 | 56 | return cell; 57 | } 58 | 59 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 60 | { 61 | return 1; 62 | } 63 | 64 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 65 | { 66 | return 20; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/MainViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.h 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MainViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/MainViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.m 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import "MainViewController.h" 10 | #import "AppDelegate.h" 11 | #import "BSPanViewController.h" 12 | 13 | @interface MainViewController () 14 | @end 15 | 16 | @implementation MainViewController 17 | 18 | #pragma mark - 19 | #pragma mark Lifecycle 20 | 21 | - (void)viewDidLoad 22 | { 23 | [super viewDidLoad]; 24 | 25 | self.title = @"BSPanViewController"; 26 | 27 | self.view.backgroundColor = [UIColor whiteColor]; 28 | self.navigationController.navigationBar.translucent = NO; 29 | 30 | UITableView *tableView = [UITableView new]; 31 | tableView.translatesAutoresizingMaskIntoConstraints = NO; 32 | tableView.dataSource = self; 33 | tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 34 | [self.view addSubview:tableView]; 35 | 36 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[tableView]|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(tableView)]]; 37 | [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(tableView)]]; 38 | 39 | UIImage *menuImage = [UIImage imageNamed:@"Menu"]; 40 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:menuImage style:UIBarButtonItemStyleBordered target:self action:@selector(menuButtonPressed:)]; 41 | } 42 | 43 | #pragma mark - 44 | #pragma mark Private Methods 45 | 46 | - (void)menuButtonPressed:(id)sender 47 | { 48 | [TheAppDelegate.panController toggleLeft]; 49 | } 50 | 51 | #pragma mark - 52 | #pragma mark Table View Data Source 53 | 54 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 55 | { 56 | static NSString *cellIdentifier = @"Cell"; 57 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 58 | if (!cell) 59 | { 60 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 61 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 62 | } 63 | 64 | cell.textLabel.text = @"BSPanViewController"; 65 | 66 | return cell; 67 | } 68 | 69 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 70 | { 71 | return 1; 72 | } 73 | 74 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 75 | { 76 | return 20; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/RightViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RightViewController.h 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import "SideViewController.h" 10 | 11 | @interface RightViewController : SideViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/RightViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RightViewController.m 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import "RightViewController.h" 10 | 11 | @implementation RightViewController 12 | 13 | #pragma mark - 14 | #pragma mark Lifecycle 15 | 16 | - (void)viewDidLoad 17 | { 18 | [super viewDidLoad]; 19 | 20 | self.backgroundImageView.image = [UIImage imageNamed:@"RightBackground"]; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/SideViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SideViewController.h 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SideViewController : UIViewController 12 | 13 | @property (nonatomic, readonly) UIImageView *backgroundImageView; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/Example/Source/Controllers/SideViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SideViewController.m 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import "SideViewController.h" 10 | 11 | @implementation SideViewController 12 | 13 | #pragma mark 14 | #pragma mark Lifecycle 15 | 16 | - (void)viewDidLoad 17 | { 18 | [super viewDidLoad]; 19 | 20 | self.view.backgroundColor = [UIColor whiteColor]; 21 | 22 | _backgroundImageView = [UIImageView new]; 23 | _backgroundImageView.frame = self.view.bounds; 24 | _backgroundImageView.contentMode = UIViewContentModeCenter; 25 | [self.view addSubview:_backgroundImageView]; 26 | } 27 | 28 | - (void)dealloc 29 | { 30 | _backgroundImageView = nil; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Example/Example/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/Example/main.m: -------------------------------------------------------------------------------- 1 | 2 | // main.m 3 | // Example 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Example/ExampleTests/ExampleTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | dk.intuitaps.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/ExampleTests/ExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleTests.m 3 | // ExampleTests 4 | // 5 | // Created by Simon Støvring on 17/11/13. 6 | // Copyright (c) 2013 intuitaps. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ExampleTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation ExampleTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Example/ExampleTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Simon B. Støvring 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BSPanViewController 2 | 3 | BSPanViewController is my take on the popular side menu. You can have a controller to be revealed in both the left and the right side. 4 | You can optionally have the controller move the status bar along with the main view. This is shown in the animation below where the status bar moves with the view when opening the left side but stays in place when opening the right side. 5 | The controller also makes it easy to add and configure a parallax effect when opening and closing the sides. The parallax effect is optional. 6 | 7 |

8 | Screenshot 9 |

10 | 11 | ## Requirements 12 | 13 | - BSPanViewController requires ARC to be enabled. If you are not already using ARC, now is a good time. 14 | - The control does only support iOS 7. 15 | 16 | ## Installation 17 | 18 | If you are using CocoaPods (which you should!) you can just add the following to your podfile and run `pod install`. 19 | 20 | pod 'BSPanViewController', :git => 'https://github.com/simonbs/BSPanViewController.git' 21 | 22 | If you are not not using CocoaPods, you should clone this repository and copy BSPanViewController/ directory into your project. 23 | 24 | When you have installed BSPanViewController either using CocoaPods or not, you just need to import the `BSPanViewController.h`. 25 | 26 | #import "BSPanViewController.h" 27 | 28 | ## Usage 29 | 30 | Using BSPanViewController is easy peasy. You just initialize an instance of BSPanViewController and then you will (usually) set it as the root view controller on your instance of `UIWindow` in the app delegate. 31 | 32 | If you want to use the pan gesture you must enable this using `leftPanEnabled` and `rightPanEnabled`. 33 | 34 | You set `mainController` which is the controller which can be dragged. That is, it is the top most controller. `leftController` and `rightController` are both shown below the main controller. These are the controllers that can be revealed when dragging the main controller. You can have both a left and a right controller or just one of them. 35 | 36 | self.panController = [BSPanViewController new]; 37 | self.panController.leftPanEnabled = YES; 38 | self.panController.rightPanEnabled = YES; 39 | self.panController.mainController = navigationController; 40 | self.panController.leftController = [LeftViewController new]; 41 | self.panController.rightController = [RightViewController new]; 42 | 43 | BSPanViewController has a lot of settings which can be set independently for the left and the right side. Please take a look at `BSPanViewController.h` for more information on the settings. 44 | 45 | The control works with `UIViewControllerBasedStatusBarAppearance` set to `YES` or `NO`. If you have the value set to `YES` you might want to subclass BSPanViewController and implemenet `-preferredStatusBarStyle` to decide the style of the status bar. 46 | 47 | ## Known Issues 48 | 49 | - There are issues with the colors of the snapshot taken of the status bar when your navigation bar is translucent. 50 | 51 | Let me know if you find anything else. 52 | 53 | ## Demo Project 54 | 55 | The repsitory contains a simple example project. This project was used to create the animation shown above. 56 | 57 | ## Credits 58 | 59 | BSPanViewController is developed by [@simonbs](http://twitter.com/simonbs), [simonbs.dk](http://simonbs.dk) Feel free to fork the repository and send pull requests if you have made something awesome. 60 | 61 | ## License 62 | 63 | BSPanViewController is released under the MIT license. Please see the LICENSE file for more information. -------------------------------------------------------------------------------- /screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simonbs/BSPanViewController/49161ca29b243790673a3b4deaf0922530db6ec6/screenshot.gif --------------------------------------------------------------------------------