├── License ├── RKLayout ├── RKFrameAdjustBlockManager.h ├── RKFrameAdjustBlockManager.m ├── RKLayout.h ├── RKLayout.m ├── RKSpacer.h ├── RKSpacer.m ├── RKSynthesizeSigleton.h ├── UIView+RKLayoutUtil.h └── UIView+RKLayoutUtil.m ├── RKLayoutExample ├── RKLayoutExample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── rkovacevic.xcuserdatad │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── WorkspaceSettings.xcsettings │ └── xcuserdata │ │ └── rkovacevic.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints.xcbkptlist │ │ └── xcschemes │ │ ├── RKLayoutExample.xcscheme │ │ └── xcschememanagement.plist └── RKLayoutExample │ ├── RKAppDelegate.h │ ├── RKAppDelegate.m │ ├── RKLayoutExample-Info.plist │ ├── RKLayoutExample-Prefix.pch │ ├── RKViewController.h │ ├── RKViewController.m │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m └── Readme.textile /License: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Robert Kovačević 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Robert Kovačević nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /RKLayout/RKFrameAdjustBlockManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // RKFrameAdjustBlockManager.h 3 | // RKLayoutExample 4 | // 5 | // Created by Robert Kovačević on 12/19/11. 6 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RKFrameAdjustBlockManager : NSObject 12 | 13 | @property (nonatomic, assign) BOOL insideFrameAdjustBlock; 14 | @property (nonatomic, assign) CGRect frame; 15 | 16 | + (RKFrameAdjustBlockManager*)sharedRKFrameAdjustBlockManager; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /RKLayout/RKFrameAdjustBlockManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // RKFrameAdjustBlockManager.m 3 | // RKLayoutExample 4 | // 5 | // Created by Robert Kovačević on 12/19/11. 6 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 7 | // 8 | 9 | #import "RKFrameAdjustBlockManager.h" 10 | #import "RKSynthesizeSigleton.h" 11 | 12 | @implementation RKFrameAdjustBlockManager 13 | 14 | @synthesize insideFrameAdjustBlock; 15 | @synthesize frame; 16 | 17 | SYNTHESIZE_SINGLETON_FOR_CLASS(RKFrameAdjustBlockManager); 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /RKLayout/RKLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // RKLayout.h 3 | // 4 | // Created by Robert Kovačević on 12/17/11. 5 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | #define RKLayoutVersion 1.1 11 | 12 | typedef enum { 13 | RKLayoutModeHorizontal, 14 | RKLayoutModeVertical, 15 | RKLayoutModeGrid 16 | } RKLayoutMode; 17 | 18 | typedef enum { 19 | RKLayoutSpacingModeFixed, 20 | RKLayoutSpacingModeAuto 21 | } RKLayoutSpacingMode; 22 | 23 | typedef enum { 24 | RKLayoutHorizontalAlignLeft, 25 | RKLayoutHorizontalAlignRight, 26 | RKLayoutHorizontalAlignCenter 27 | } RKLayoutHorizontalAlign; 28 | 29 | typedef enum { 30 | RKLayoutVerticalAlignTop, 31 | RKLayoutVerticalAlignBottom, 32 | RKLayoutVerticalAlignCenter 33 | } RKLayoutVerticalAlign; 34 | 35 | @interface RKLayout : UIView 36 | 37 | @property (nonatomic, assign) RKLayoutMode layoutMode; // default is RKLayoutModeHorizontal 38 | @property (nonatomic, assign) RKLayoutSpacingMode spacingMode; // default is RKLayoutSpacingModeFixed 39 | @property (nonatomic, assign) RKLayoutHorizontalAlign horizontalAlign; // default is RKLayoutHorizontalAlignLeft 40 | @property (nonatomic, assign) RKLayoutVerticalAlign verticalAlign; // default is RKLayoutVerticalAlignTop 41 | @property (nonatomic, assign) CGFloat spacing; // spacing between subviews, default is zero 42 | 43 | - (id)initWithFrame:(CGRect)frame withSpacing:(CGFloat)spacing; 44 | - (id)initWithFrame:(CGRect)frame withMode:(RKLayoutMode)mode withSpacing:(CGFloat)spacing; 45 | - (id)initWithFrame:(CGRect)frame withMode:(RKLayoutMode)mode; 46 | 47 | - (CGSize)contentSize; 48 | 49 | @end 50 | 51 | @interface RKLayout (RKLayoutPositioning) 52 | 53 | + (void)positionView:(UIView*)view rightOfView:(UIView*)baseView; 54 | + (void)positionView:(UIView*)view rightOfView:(UIView*)baseView withSpacing:(CGFloat)spacing; 55 | 56 | + (void)positionView:(UIView*)view leftOfView:(UIView*)baseView; 57 | + (void)positionView:(UIView*)view leftOfView:(UIView*)baseView withSpacing:(CGFloat)spacing; 58 | 59 | + (void)positionView:(UIView*)view aboveView:(UIView*)baseView; 60 | + (void)positionView:(UIView*)view aboveView:(UIView*)baseView withSpacing:(CGFloat)spacing; 61 | 62 | + (void)positionView:(UIView*)view bellowView:(UIView*)baseView; 63 | + (void)positionView:(UIView*)view bellowView:(UIView*)baseView withSpacing:(CGFloat)spacing; 64 | 65 | + (void)centerView:(UIView*)view inFrame:(CGRect)frame; 66 | 67 | + (void)placeView:(UIView*)view inFrame:(CGRect)frame withHorizontalAlign:(RKLayoutHorizontalAlign)horizontalAlign withVerticalAlign:(RKLayoutVerticalAlign)verticalAlign; 68 | 69 | @end 70 | 71 | CG_INLINE CGRect 72 | RKOriginRectMake(CGFloat width, CGFloat height) 73 | { 74 | CGRect rect; 75 | rect.origin.x = 0; rect.origin.y = 0; 76 | rect.size.width = width; rect.size.height = height; 77 | return rect; 78 | } 79 | -------------------------------------------------------------------------------- /RKLayout/RKLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // RKLayout.m 3 | // 4 | // Created by Robert Kovačević on 12/17/11. 5 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 6 | // 7 | 8 | #import "RKLayout.h" 9 | #import "UIView+RKLayoutUtil.h" 10 | #import "RKFrameAdjustBlockManager.h" 11 | 12 | @interface RKLayout () 13 | 14 | - (CGSize)contentSizeVertical; 15 | - (CGSize)contentSizeHorizontal; 16 | - (CGSize)contentSizeGrid; 17 | 18 | - (void)layoutSubviewsVertical; 19 | - (void)layoutSubviewsHorizontal; 20 | - (void)layoutSubviewsGrid; 21 | 22 | - (CGFloat)horizontalAlignMargin; 23 | - (CGFloat)verticalAlignMargin; 24 | 25 | - (CGFloat)gridAutoSpacing; 26 | - (NSUInteger)gridNumberOfColumns; 27 | 28 | @end 29 | 30 | @implementation RKLayout 31 | 32 | @synthesize layoutMode = _layoutMode; 33 | @synthesize spacingMode = _spacingMode; 34 | @synthesize horizontalAlign = _horizontalAlign; 35 | @synthesize verticalAlign = _verticalAlign; 36 | @synthesize spacing = _spacing; 37 | 38 | #pragma mark - Initialization 39 | 40 | - (id)initWithFrame:(CGRect)frame 41 | { 42 | self = [super initWithFrame:frame]; 43 | if (self) { 44 | // Set defaults 45 | _layoutMode = RKLayoutModeHorizontal; 46 | _spacingMode = RKLayoutSpacingModeFixed; 47 | _horizontalAlign = RKLayoutHorizontalAlignLeft; 48 | _verticalAlign = RKLayoutVerticalAlignTop; 49 | _spacing = 0; 50 | } 51 | return self; 52 | } 53 | 54 | - (id)initWithFrame:(CGRect)frame withSpacing:(CGFloat)spacing 55 | { 56 | self = [self initWithFrame:frame]; 57 | if (self) { 58 | _spacing = spacing; 59 | } 60 | return self; 61 | } 62 | 63 | - (id)initWithFrame:(CGRect)frame withMode:(RKLayoutMode)mode withSpacing:(CGFloat)spacing 64 | { 65 | self = [self initWithFrame:frame withSpacing:spacing]; 66 | if (self) { 67 | _layoutMode = mode; 68 | } 69 | return self; 70 | } 71 | 72 | - (id)initWithFrame:(CGRect)frame withMode:(RKLayoutMode)mode 73 | { 74 | return [self initWithFrame:frame withMode:mode withSpacing:0.0f]; 75 | } 76 | 77 | #pragma mark - Public 78 | 79 | - (void)setLayoutMode:(RKLayoutMode)layoutMode 80 | { 81 | _layoutMode = layoutMode; 82 | [self setNeedsLayout]; 83 | } 84 | 85 | - (void)setSpacingMode:(RKLayoutSpacingMode)spacingMode 86 | { 87 | _spacingMode = spacingMode; 88 | [self setNeedsLayout]; 89 | } 90 | 91 | - (void)setHorizontalAlign:(RKLayoutHorizontalAlign)horizontalAlign 92 | { 93 | _horizontalAlign = horizontalAlign; 94 | [self setNeedsLayout]; 95 | } 96 | 97 | - (void)setVerticalAlign:(RKLayoutVerticalAlign)verticalAlign 98 | { 99 | _verticalAlign = verticalAlign; 100 | [self setNeedsLayout]; 101 | } 102 | 103 | - (CGSize)contentSize 104 | { 105 | switch (self.layoutMode) { 106 | case RKLayoutModeVertical: 107 | return [self contentSizeVertical]; 108 | case RKLayoutModeGrid: 109 | return [self contentSizeGrid]; 110 | default: 111 | return [self contentSizeHorizontal]; 112 | } 113 | } 114 | 115 | #pragma mark - UIView overrides 116 | 117 | - (void)layoutSubviews 118 | { 119 | switch (self.layoutMode) { 120 | case RKLayoutModeVertical: 121 | [self layoutSubviewsVertical]; 122 | break; 123 | case RKLayoutModeGrid: 124 | [self layoutSubviewsGrid]; 125 | break; 126 | default: 127 | [self layoutSubviewsHorizontal]; 128 | break; 129 | } 130 | } 131 | 132 | #pragma mark - Private 133 | 134 | - (void)layoutSubviewsHorizontal 135 | { 136 | CGFloat horizontalAlignMargin = self.horizontalAlignMargin; 137 | CGFloat verticalAlignMargin = self.verticalAlignMargin; 138 | 139 | CGFloat spacing = self.spacing; 140 | if (self.spacingMode == RKLayoutSpacingModeAuto) 141 | { 142 | spacing = (self.frameWidth - self.sumOfSubviewWidths) / (self.subviews.count + 1); 143 | } 144 | 145 | CGFloat maxSubviewHeight = self.maxSubviewWidth; 146 | 147 | CGFloat currentX = horizontalAlignMargin + spacing; 148 | for (UIView* subview in self.subviews) 149 | { 150 | CGFloat frameX = currentX; 151 | CGFloat frameY = verticalAlignMargin; 152 | if (self.verticalAlign == RKLayoutVerticalAlignCenter) 153 | { 154 | frameY = frameY + (maxSubviewHeight - subview.frameHeight) / 2; 155 | } 156 | else if (self.verticalAlign == RKLayoutVerticalAlignBottom) 157 | { 158 | frameY = frameY + (maxSubviewHeight - subview.frameHeight); 159 | } 160 | subview.frame = CGRectMake(frameX, frameY, subview.frameWidth, subview.frameHeight); 161 | currentX += spacing + subview.frameWidth; 162 | } 163 | } 164 | 165 | - (void)layoutSubviewsVertical 166 | { 167 | CGFloat horizontalAlignMargin = self.horizontalAlignMargin; 168 | CGFloat verticalAlignMargin = self.verticalAlignMargin; 169 | 170 | CGFloat spacing = self.spacing; 171 | if (self.spacingMode == RKLayoutSpacingModeAuto) 172 | { 173 | spacing = (self.frameHeight - self.sumOfSubviewHeights) / (self.subviews.count + 1); 174 | } 175 | 176 | CGFloat maxSubviewWidth = self.maxSubviewWidth; 177 | 178 | CGFloat currentY = verticalAlignMargin + spacing; 179 | for (UIView* subview in self.subviews) 180 | { 181 | CGFloat frameY = currentY; 182 | CGFloat frameX = horizontalAlignMargin; 183 | if (self.horizontalAlign == RKLayoutHorizontalAlignCenter) 184 | { 185 | frameX = frameX + (maxSubviewWidth - subview.frameWidth) / 2; 186 | } 187 | else if (self.horizontalAlign == RKLayoutHorizontalAlignRight) 188 | { 189 | frameX = frameX + (maxSubviewWidth - subview.frameWidth); 190 | } 191 | subview.frame = CGRectMake(frameX, frameY, subview.frameWidth, subview.frameHeight); 192 | currentY += spacing + subview.frameHeight; 193 | } 194 | } 195 | 196 | - (void)layoutSubviewsGrid 197 | { 198 | CGFloat horizontalAlignMargin = self.horizontalAlignMargin; 199 | CGFloat verticalAlignMargin = self.verticalAlignMargin; 200 | 201 | CGFloat maxSubviewWidth = self.maxSubviewWidth; 202 | CGFloat maxSubviewHeight = self.maxSubviewHeight; 203 | 204 | CGFloat spacing = self.spacing; 205 | if (self.spacingMode == RKLayoutSpacingModeAuto) 206 | { 207 | spacing = self.gridAutoSpacing; 208 | } 209 | 210 | NSUInteger numberOfColumns = [self gridNumberOfColumns]; 211 | NSUInteger numberOfRows = lroundf(ceilf([[NSNumber numberWithInt:self.subviews.count] floatValue] / [[NSNumber numberWithInt:numberOfColumns] floatValue])); 212 | 213 | NSUInteger currentCell = 0; 214 | 215 | for (NSInteger row = 0; row < numberOfRows; row++) 216 | { 217 | for (NSInteger column = 0; column < numberOfColumns; column++) 218 | { 219 | UIView* subview = [self.subviews objectAtIndex:currentCell]; 220 | 221 | CGFloat cellFrameX = horizontalAlignMargin + (column + 1) * spacing + column * maxSubviewWidth; 222 | CGFloat cellFrameY = verticalAlignMargin + (row + 1) * spacing + row * maxSubviewHeight; 223 | 224 | CGRect cellFrame = CGRectMake(cellFrameX, cellFrameY, maxSubviewWidth, maxSubviewHeight); 225 | 226 | [RKLayout placeView:subview 227 | inFrame:cellFrame 228 | withHorizontalAlign:self.horizontalAlign 229 | withVerticalAlign:self.verticalAlign]; 230 | 231 | currentCell++; 232 | 233 | if (currentCell >= self.subviews.count) return; 234 | } 235 | } 236 | } 237 | 238 | - (CGFloat)horizontalAlignMargin 239 | { 240 | if (self.layoutMode == RKLayoutModeHorizontal && 241 | self.spacingMode == RKLayoutSpacingModeAuto) return 0.0f; 242 | 243 | CGSize contentSize = self.contentSize; 244 | CGFloat horizontalAlignMargin = 0.0f; 245 | switch (self.horizontalAlign) { 246 | case RKLayoutHorizontalAlignCenter: 247 | horizontalAlignMargin = (self.frameWidth - contentSize.width) / 2; 248 | break; 249 | case RKLayoutHorizontalAlignRight: 250 | horizontalAlignMargin = self.frameWidth - contentSize.width; 251 | break; 252 | default: 253 | horizontalAlignMargin = 0.0f; 254 | break; 255 | } 256 | 257 | return MAX(0.0f, horizontalAlignMargin); 258 | } 259 | 260 | - (CGFloat)verticalAlignMargin 261 | { 262 | if (self.layoutMode == RKLayoutModeVertical && 263 | self.spacingMode == RKLayoutSpacingModeAuto) return 0.0f; 264 | 265 | CGSize contentSize = self.contentSize; 266 | 267 | CGFloat verticalAlignMargin = 0.0f; 268 | switch (self.verticalAlign) { 269 | case RKLayoutVerticalAlignCenter: 270 | verticalAlignMargin = (self.frameHeight - contentSize.height) / 2; 271 | break; 272 | case RKLayoutVerticalAlignBottom: 273 | verticalAlignMargin = self.frameHeight - contentSize.height; 274 | break; 275 | default: 276 | verticalAlignMargin = 0.0f; 277 | break; 278 | } 279 | 280 | return MAX(0.0f, verticalAlignMargin); 281 | } 282 | 283 | - (CGSize)contentSizeHorizontal 284 | { 285 | CGFloat maxSubviewHeight = 0.0f; 286 | CGFloat contentWidth = self.spacing; 287 | 288 | for (UIView* subview in self.subviews) 289 | { 290 | contentWidth += subview.frameWidth + self.spacing; 291 | maxSubviewHeight = MAX(maxSubviewHeight, subview.frameHeight); 292 | } 293 | 294 | switch (self.spacingMode) { 295 | case RKLayoutSpacingModeFixed: 296 | return CGSizeMake(contentWidth, maxSubviewHeight); 297 | default: 298 | return CGSizeMake(self.frameWidth, maxSubviewHeight); 299 | } 300 | } 301 | 302 | - (CGSize)contentSizeVertical 303 | { 304 | CGFloat maxSubviewWidth = 0.0f; 305 | CGFloat contentHeight = self.spacing; 306 | 307 | for (UIView* subview in self.subviews) 308 | { 309 | contentHeight += subview.frameHeight + self.spacing; 310 | maxSubviewWidth = MAX(maxSubviewWidth, subview.frameWidth); 311 | } 312 | 313 | switch (self.spacingMode) { 314 | case RKLayoutSpacingModeFixed: 315 | return CGSizeMake(maxSubviewWidth, contentHeight); 316 | default: 317 | return CGSizeMake(maxSubviewWidth, self.frameHeight); 318 | } 319 | } 320 | 321 | - (CGSize)contentSizeGrid 322 | { 323 | CGFloat spacing = self.spacing; 324 | if (self.spacingMode == RKLayoutSpacingModeAuto) 325 | { 326 | spacing = self.gridAutoSpacing; 327 | } 328 | 329 | CGFloat maxSubviewWidth = self.maxSubviewWidth; 330 | CGFloat maxSubviewHeight = self.maxSubviewHeight; 331 | 332 | NSInteger numberOfRows = 1; 333 | NSInteger currentColumn = 0; 334 | NSInteger currentRow = 0; 335 | CGFloat currentColumnWidth = spacing; 336 | CGFloat contentWidth = 0.0f; 337 | CGFloat contentHeight = spacing + maxSubviewHeight; 338 | for (UIView* subview in self.subviews) 339 | { 340 | if (currentColumn > 0 && (currentColumnWidth + maxSubviewWidth + spacing) > self.frameWidth) 341 | { 342 | // Next row 343 | currentRow++; 344 | numberOfRows++; 345 | currentColumn = 0; 346 | currentColumnWidth = spacing; 347 | contentHeight += spacing + maxSubviewHeight; 348 | } 349 | currentColumnWidth += maxSubviewWidth + spacing; 350 | currentColumn++; 351 | contentWidth = MAX(contentWidth, currentColumnWidth); 352 | } 353 | 354 | return CGSizeMake(contentWidth, contentHeight); 355 | } 356 | 357 | - (CGFloat)gridAutoSpacing 358 | { 359 | NSUInteger numberOfColumnsOrRows = lroundf(sqrtf(self.subviews.count)); 360 | CGFloat largerDimension = MAX(self.maxSubviewWidth, self.maxSubviewHeight); 361 | return (self.frameHeight - (numberOfColumnsOrRows * largerDimension)) / (self.subviews.count + 1); 362 | } 363 | 364 | - (NSUInteger)gridNumberOfColumns 365 | { 366 | CGFloat spacing = self.spacing; 367 | if (self.spacingMode == RKLayoutSpacingModeAuto) 368 | { 369 | spacing = self.gridAutoSpacing; 370 | } 371 | 372 | CGFloat maxSubviewWidth = self.maxSubviewWidth; 373 | 374 | NSInteger numberOfColumns = 0; 375 | NSInteger currentColumn = 0; 376 | NSInteger currentRow = 0; 377 | CGFloat currentColumnWidth = spacing; 378 | for (UIView* subview in self.subviews) 379 | { 380 | if (currentColumn > 0 && (currentColumnWidth + maxSubviewWidth + spacing) > self.frameWidth) 381 | { 382 | // Next row 383 | currentRow++; 384 | currentColumn = 0; 385 | currentColumnWidth = spacing; 386 | } 387 | currentColumnWidth += maxSubviewWidth + spacing; 388 | currentColumn++; 389 | numberOfColumns = MAX(numberOfColumns, currentColumn); 390 | } 391 | 392 | return numberOfColumns; 393 | } 394 | 395 | @end 396 | 397 | @implementation RKLayout (RKLayoutPositioning) 398 | 399 | + (void)positionView:(UIView*)view rightOfView:(UIView*)baseView 400 | { 401 | [RKLayout positionView:view rightOfView:baseView withSpacing:0.0f]; 402 | } 403 | 404 | + (void)positionView:(UIView*)view rightOfView:(UIView*)baseView withSpacing:(CGFloat)spacing 405 | { 406 | if (baseView == nil) 407 | { 408 | view.frameX = spacing; 409 | return; 410 | } 411 | 412 | view.frameX = baseView.frameX + baseView.frameWidth + spacing; 413 | } 414 | 415 | + (void)positionView:(UIView*)view leftOfView:(UIView*)baseView 416 | { 417 | [RKLayout positionView:view leftOfView:baseView withSpacing:0.0f]; 418 | } 419 | 420 | + (void)positionView:(UIView*)view leftOfView:(UIView*)baseView withSpacing:(CGFloat)spacing 421 | { 422 | if (baseView == nil) 423 | { 424 | view.frameX = -view.frameWidth; 425 | return; 426 | } 427 | 428 | view.frameX = baseView.frameX - spacing - view.frameWidth; 429 | } 430 | 431 | + (void)positionView:(UIView*)view aboveView:(UIView*)baseView 432 | { 433 | [RKLayout positionView:view aboveView:baseView withSpacing:0.0f]; 434 | } 435 | 436 | + (void)positionView:(UIView*)view aboveView:(UIView*)baseView withSpacing:(CGFloat)spacing 437 | { 438 | if (baseView == nil) 439 | { 440 | view.frameY = -view.frameHeight; 441 | return; 442 | } 443 | 444 | view.frameY = baseView.frameY - spacing - view.frameHeight; 445 | } 446 | 447 | + (void)positionView:(UIView*)view bellowView:(UIView*)baseView 448 | { 449 | [RKLayout positionView:view bellowView:baseView withSpacing:0.0f]; 450 | } 451 | 452 | + (void)positionView:(UIView*)view bellowView:(UIView*)baseView withSpacing:(CGFloat)spacing 453 | { 454 | if (baseView == nil) 455 | { 456 | view.frameY = spacing; 457 | return; 458 | } 459 | 460 | view.frameY = baseView.frameY + baseView.frameHeight + spacing; 461 | } 462 | 463 | + (void)centerView:(UIView*)view inFrame:(CGRect)frame 464 | { 465 | [RKLayout placeView:view 466 | inFrame:frame 467 | withHorizontalAlign:RKLayoutHorizontalAlignCenter 468 | withVerticalAlign:RKLayoutVerticalAlignCenter]; 469 | } 470 | 471 | + (void)placeView:(UIView*)view inFrame:(CGRect)frame withHorizontalAlign:(RKLayoutHorizontalAlign)horizontalAlign withVerticalAlign:(RKLayoutVerticalAlign)verticalAlign 472 | { 473 | [view beginFrameAdjust]; 474 | switch (horizontalAlign) { 475 | case RKLayoutHorizontalAlignLeft: 476 | view.frameX = frame.origin.x; 477 | break; 478 | case RKLayoutHorizontalAlignCenter: 479 | view.frameX = frame.origin.x + (frame.size.width - view.frameWidth) / 2; 480 | break; 481 | default: 482 | view.frameX = frame.origin.x + (frame.size.width - view.frameWidth); 483 | break; 484 | } 485 | 486 | switch (verticalAlign) { 487 | case RKLayoutVerticalAlignTop: 488 | view.frameY = frame.origin.y; 489 | break; 490 | case RKLayoutVerticalAlignCenter: 491 | view.frameY = frame.origin.y + (frame.size.height - view.frameHeight) / 2; 492 | break; 493 | default: 494 | view.frameY = frame.origin.y + (frame.size.height - view.frameHeight); 495 | break; 496 | } 497 | [view commitFrameAdjust]; 498 | } 499 | 500 | @end 501 | 502 | -------------------------------------------------------------------------------- /RKLayout/RKSpacer.h: -------------------------------------------------------------------------------- 1 | // 2 | // RKSpacer.h 3 | // 4 | // Created by Robert Kovačević on 12/19/11. 5 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface RKSpacer : UIView 11 | 12 | + (id)spacerWithWidth:(CGFloat)width withHeight:(CGFloat)height; 13 | + (id)spacerWithWidth:(CGFloat)width; 14 | + (id)spacerWithHeight:(CGFloat)height; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /RKLayout/RKSpacer.m: -------------------------------------------------------------------------------- 1 | // 2 | // RKSpacer.m 3 | // 4 | // Created by Robert Kovačević on 12/19/11. 5 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 6 | // 7 | 8 | #import "RKSpacer.h" 9 | #import "RKLayout.h" 10 | 11 | @implementation RKSpacer 12 | 13 | - (id)initWithFrame:(CGRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | self.backgroundColor = [UIColor clearColor]; 18 | self.userInteractionEnabled = NO; 19 | } 20 | return self; 21 | } 22 | 23 | + (id)spacerWithWidth:(CGFloat)width withHeight:(CGFloat)height 24 | { 25 | return [[RKSpacer alloc] initWithFrame:RKOriginRectMake(width, height)]; 26 | } 27 | 28 | + (id)spacerWithWidth:(CGFloat)width 29 | { 30 | return [RKSpacer spacerWithWidth:width withHeight:0.0f]; 31 | } 32 | 33 | + (id)spacerWithHeight:(CGFloat)height 34 | { 35 | return [RKSpacer spacerWithWidth:0.0f withHeight:height]; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /RKLayout/RKSynthesizeSigleton.h: -------------------------------------------------------------------------------- 1 | // 2 | // SynthesizeSingleton.h 3 | // CocoaWithLove 4 | // 5 | // Created by Matt Gallagher on 20/10/08. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file without charge in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \ 16 | \ 17 | static classname *shared##classname = nil; \ 18 | \ 19 | + (classname *)shared##classname \ 20 | { \ 21 | @synchronized(self) \ 22 | { \ 23 | if (shared##classname == nil) \ 24 | { \ 25 | shared##classname = [[self alloc] init]; \ 26 | } \ 27 | } \ 28 | \ 29 | return shared##classname; \ 30 | } \ 31 | \ 32 | + (id)allocWithZone:(NSZone *)zone \ 33 | { \ 34 | @synchronized(self) \ 35 | { \ 36 | if (shared##classname == nil) \ 37 | { \ 38 | shared##classname = [super allocWithZone:zone]; \ 39 | return shared##classname; \ 40 | } \ 41 | } \ 42 | \ 43 | return nil; \ 44 | } \ 45 | \ 46 | - (id)copyWithZone:(NSZone *)zone \ 47 | { \ 48 | return self; \ 49 | } \ 50 | \ 51 | -------------------------------------------------------------------------------- /RKLayout/UIView+RKLayoutUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+NTHLayoutUtil.h 3 | // 4 | // Created by Robert Kovačević on 12/17/11. 5 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface UIView (RKLayoutUtil) 11 | 12 | - (void)beginFrameAdjust; 13 | - (void)commitFrameAdjust; 14 | 15 | // Frame getter / setter helpers 16 | 17 | - (CGFloat)frameWidth; 18 | - (void)setFrameWidth:(CGFloat)width; 19 | 20 | - (CGFloat)frameHeight; 21 | - (void)setFrameHeight:(CGFloat)height; 22 | 23 | - (CGFloat)frameX; 24 | - (void)setFrameX:(CGFloat)x; 25 | 26 | - (CGFloat)frameY; 27 | - (void)setFrameY:(CGFloat)y; 28 | 29 | // Common calculations 30 | 31 | - (CGFloat)sumOfSubviewWidths; 32 | - (CGFloat)sumOfSubviewHeights; 33 | - (CGFloat)maxSubviewWidth; 34 | - (CGFloat)maxSubviewHeight; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /RKLayout/UIView+RKLayoutUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+NTHLayoutUtil.m 3 | // 4 | // Created by Robert Kovačević on 12/17/11. 5 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 6 | // 7 | 8 | #import "UIView+RKLayoutUtil.h" 9 | #import "RKFrameAdjustBlockManager.h" 10 | 11 | @interface UIView () 12 | 13 | - (CGFloat)roundToPixel:(CGFloat)value; 14 | - (BOOL)retinaDisplay; 15 | 16 | @end 17 | 18 | @implementation UIView (RKLayoutUtil) 19 | 20 | - (void)beginFrameAdjust 21 | { 22 | [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].insideFrameAdjustBlock = YES; 23 | [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame = self.frame; 24 | } 25 | 26 | - (void)commitFrameAdjust 27 | { 28 | self.frame = [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame; 29 | [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].insideFrameAdjustBlock = YES; 30 | } 31 | 32 | - (CGFloat)frameWidth 33 | { 34 | return self.frame.size.width; 35 | } 36 | 37 | - (void)setFrameWidth:(CGFloat)width 38 | { 39 | width = [self roundToPixel:width]; 40 | if ([RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].insideFrameAdjustBlock) 41 | { 42 | CGRect frame = [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame; 43 | frame = CGRectMake(frame.origin.x, frame.origin.y, width, frame.size.height); 44 | [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame = frame; 45 | } 46 | else 47 | { 48 | self.frame = CGRectMake(self.frameX, self.frameY, width, self.frameHeight); 49 | } 50 | } 51 | 52 | - (CGFloat)frameHeight 53 | { 54 | return self.frame.size.height; 55 | } 56 | 57 | - (void)setFrameHeight:(CGFloat)height 58 | { 59 | height = [self roundToPixel:height]; 60 | if ([RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].insideFrameAdjustBlock) 61 | { 62 | CGRect frame = [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame; 63 | frame = CGRectMake(frame.origin.x, frame.origin.y, frame.size.height, height); 64 | [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame = frame; 65 | } 66 | else 67 | { 68 | self.frame = CGRectMake(self.frameX, self.frameY, self.frameWidth, height); 69 | } 70 | } 71 | 72 | - (CGFloat)frameX 73 | { 74 | return self.frame.origin.x; 75 | } 76 | 77 | - (void)setFrameX:(CGFloat)x 78 | { 79 | x = [self roundToPixel:x]; 80 | if ([RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].insideFrameAdjustBlock) 81 | { 82 | CGRect frame = [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame; 83 | frame = CGRectMake(x, frame.origin.y, frame.size.width, frame.size.height); 84 | [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame = frame; 85 | } 86 | else 87 | { 88 | self.frame = CGRectMake(x, self.frameY, self.frameWidth, self.frameHeight); 89 | } 90 | } 91 | 92 | - (CGFloat)frameY 93 | { 94 | return self.frame.origin.y; 95 | } 96 | 97 | - (void)setFrameY:(CGFloat)y 98 | { 99 | y = [self roundToPixel:y]; 100 | if ([RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].insideFrameAdjustBlock) 101 | { 102 | CGRect frame = [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame; 103 | frame = CGRectMake(frame.origin.x, y, frame.size.width, frame.size.height); 104 | [RKFrameAdjustBlockManager sharedRKFrameAdjustBlockManager].frame = frame; 105 | } 106 | else 107 | { 108 | self.frame = CGRectMake(self.frameX, y, self.frameWidth, self.frameHeight); 109 | } 110 | } 111 | 112 | - (CGFloat)sumOfSubviewWidths 113 | { 114 | CGFloat sumOfSubviewWidths = 0.0f; 115 | for (UIView* subview in self.subviews) 116 | { 117 | sumOfSubviewWidths += subview.frameWidth; 118 | } 119 | return sumOfSubviewWidths; 120 | } 121 | 122 | - (CGFloat)sumOfSubviewHeights 123 | { 124 | CGFloat sumOfSubviewHeights = 0.0f; 125 | for (UIView* subview in self.subviews) 126 | { 127 | sumOfSubviewHeights += subview.frameHeight; 128 | } 129 | return sumOfSubviewHeights; 130 | } 131 | 132 | - (CGFloat)maxSubviewWidth 133 | { 134 | CGFloat maxSubviewWidth = 0.0f; 135 | for (UIView* subview in self.subviews) 136 | { 137 | maxSubviewWidth = MAX(maxSubviewWidth, subview.frameWidth); 138 | } 139 | return maxSubviewWidth; 140 | } 141 | 142 | - (CGFloat)maxSubviewHeight 143 | { 144 | CGFloat maxSubviewHeight = 0.0f; 145 | for (UIView* subview in self.subviews) 146 | { 147 | maxSubviewHeight = MAX(maxSubviewHeight, subview.frameHeight); 148 | } 149 | return maxSubviewHeight; 150 | } 151 | 152 | #pragma mark - Private 153 | 154 | - (CGFloat)roundToPixel:(CGFloat)value 155 | { 156 | if ([self retinaDisplay]) 157 | { 158 | return roundf(value * 2) / 2; 159 | } 160 | else 161 | { 162 | return roundf(value); 163 | } 164 | } 165 | 166 | - (BOOL)retinaDisplay 167 | { 168 | return ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2); 169 | } 170 | 171 | @end 172 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 07CEBF5C149F7460004A947E /* RKFrameAdjustBlockManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 07CEBF5B149F7460004A947E /* RKFrameAdjustBlockManager.m */; }; 11 | 07DB81DF149E719700D857A9 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07DB81DE149E719700D857A9 /* UIKit.framework */; }; 12 | 07DB81E1149E719700D857A9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07DB81E0149E719700D857A9 /* Foundation.framework */; }; 13 | 07DB81E3149E719700D857A9 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07DB81E2149E719700D857A9 /* CoreGraphics.framework */; }; 14 | 07DB81E9149E719700D857A9 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 07DB81E7149E719700D857A9 /* InfoPlist.strings */; }; 15 | 07DB81EB149E719700D857A9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 07DB81EA149E719700D857A9 /* main.m */; }; 16 | 07DB81EF149E719700D857A9 /* RKAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 07DB81EE149E719700D857A9 /* RKAppDelegate.m */; }; 17 | 07DB81F2149E719700D857A9 /* RKViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 07DB81F1149E719700D857A9 /* RKViewController.m */; }; 18 | 07DB8206149E78CB00D857A9 /* RKLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 07DB8203149E78CB00D857A9 /* RKLayout.m */; }; 19 | 07DB8207149E78CB00D857A9 /* UIView+RKLayoutUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 07DB8205149E78CB00D857A9 /* UIView+RKLayoutUtil.m */; }; 20 | 07DB820A149F3DE200D857A9 /* RKSpacer.m in Sources */ = {isa = PBXBuildFile; fileRef = 07DB8209149F3DE200D857A9 /* RKSpacer.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 07CEBF5A149F7460004A947E /* RKFrameAdjustBlockManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKFrameAdjustBlockManager.h; sourceTree = ""; }; 25 | 07CEBF5B149F7460004A947E /* RKFrameAdjustBlockManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKFrameAdjustBlockManager.m; sourceTree = ""; }; 26 | 07CEBF5D149F7654004A947E /* RKSynthesizeSigleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKSynthesizeSigleton.h; sourceTree = ""; }; 27 | 07DB81DA149E719700D857A9 /* RKLayoutExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RKLayoutExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 07DB81DE149E719700D857A9 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 29 | 07DB81E0149E719700D857A9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 30 | 07DB81E2149E719700D857A9 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 31 | 07DB81E6149E719700D857A9 /* RKLayoutExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RKLayoutExample-Info.plist"; sourceTree = ""; }; 32 | 07DB81E8149E719700D857A9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 33 | 07DB81EA149E719700D857A9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 34 | 07DB81EC149E719700D857A9 /* RKLayoutExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RKLayoutExample-Prefix.pch"; sourceTree = ""; }; 35 | 07DB81ED149E719700D857A9 /* RKAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RKAppDelegate.h; sourceTree = ""; }; 36 | 07DB81EE149E719700D857A9 /* RKAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RKAppDelegate.m; sourceTree = ""; }; 37 | 07DB81F0149E719700D857A9 /* RKViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RKViewController.h; sourceTree = ""; }; 38 | 07DB81F1149E719700D857A9 /* RKViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RKViewController.m; sourceTree = ""; }; 39 | 07DB8202149E78CB00D857A9 /* RKLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKLayout.h; sourceTree = ""; }; 40 | 07DB8203149E78CB00D857A9 /* RKLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKLayout.m; sourceTree = ""; }; 41 | 07DB8204149E78CB00D857A9 /* UIView+RKLayoutUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+RKLayoutUtil.h"; sourceTree = ""; }; 42 | 07DB8205149E78CB00D857A9 /* UIView+RKLayoutUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+RKLayoutUtil.m"; sourceTree = ""; }; 43 | 07DB8208149F3DE200D857A9 /* RKSpacer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKSpacer.h; sourceTree = ""; }; 44 | 07DB8209149F3DE200D857A9 /* RKSpacer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKSpacer.m; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 07DB81D7149E719700D857A9 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | 07DB81DF149E719700D857A9 /* UIKit.framework in Frameworks */, 53 | 07DB81E1149E719700D857A9 /* Foundation.framework in Frameworks */, 54 | 07DB81E3149E719700D857A9 /* CoreGraphics.framework in Frameworks */, 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | 07DB81CF149E719700D857A9 = { 62 | isa = PBXGroup; 63 | children = ( 64 | 07DB8201149E78CB00D857A9 /* RKLayout */, 65 | 07DB81E4149E719700D857A9 /* RKLayoutExample */, 66 | 07DB81DD149E719700D857A9 /* Frameworks */, 67 | 07DB81DB149E719700D857A9 /* Products */, 68 | ); 69 | sourceTree = ""; 70 | }; 71 | 07DB81DB149E719700D857A9 /* Products */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 07DB81DA149E719700D857A9 /* RKLayoutExample.app */, 75 | ); 76 | name = Products; 77 | sourceTree = ""; 78 | }; 79 | 07DB81DD149E719700D857A9 /* Frameworks */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 07DB81DE149E719700D857A9 /* UIKit.framework */, 83 | 07DB81E0149E719700D857A9 /* Foundation.framework */, 84 | 07DB81E2149E719700D857A9 /* CoreGraphics.framework */, 85 | ); 86 | name = Frameworks; 87 | sourceTree = ""; 88 | }; 89 | 07DB81E4149E719700D857A9 /* RKLayoutExample */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 07DB81ED149E719700D857A9 /* RKAppDelegate.h */, 93 | 07DB81EE149E719700D857A9 /* RKAppDelegate.m */, 94 | 07DB81F0149E719700D857A9 /* RKViewController.h */, 95 | 07DB81F1149E719700D857A9 /* RKViewController.m */, 96 | 07DB81E5149E719700D857A9 /* Supporting Files */, 97 | ); 98 | path = RKLayoutExample; 99 | sourceTree = ""; 100 | }; 101 | 07DB81E5149E719700D857A9 /* Supporting Files */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 07DB81E6149E719700D857A9 /* RKLayoutExample-Info.plist */, 105 | 07DB81E7149E719700D857A9 /* InfoPlist.strings */, 106 | 07DB81EA149E719700D857A9 /* main.m */, 107 | 07DB81EC149E719700D857A9 /* RKLayoutExample-Prefix.pch */, 108 | ); 109 | name = "Supporting Files"; 110 | sourceTree = ""; 111 | }; 112 | 07DB8201149E78CB00D857A9 /* RKLayout */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 07DB8202149E78CB00D857A9 /* RKLayout.h */, 116 | 07DB8203149E78CB00D857A9 /* RKLayout.m */, 117 | 07DB8204149E78CB00D857A9 /* UIView+RKLayoutUtil.h */, 118 | 07DB8205149E78CB00D857A9 /* UIView+RKLayoutUtil.m */, 119 | 07DB8208149F3DE200D857A9 /* RKSpacer.h */, 120 | 07DB8209149F3DE200D857A9 /* RKSpacer.m */, 121 | 07CEBF5A149F7460004A947E /* RKFrameAdjustBlockManager.h */, 122 | 07CEBF5B149F7460004A947E /* RKFrameAdjustBlockManager.m */, 123 | 07CEBF5D149F7654004A947E /* RKSynthesizeSigleton.h */, 124 | ); 125 | name = RKLayout; 126 | path = ../RKLayout; 127 | sourceTree = ""; 128 | }; 129 | /* End PBXGroup section */ 130 | 131 | /* Begin PBXNativeTarget section */ 132 | 07DB81D9149E719700D857A9 /* RKLayoutExample */ = { 133 | isa = PBXNativeTarget; 134 | buildConfigurationList = 07DB81FB149E719700D857A9 /* Build configuration list for PBXNativeTarget "RKLayoutExample" */; 135 | buildPhases = ( 136 | 07DB81D6149E719700D857A9 /* Sources */, 137 | 07DB81D7149E719700D857A9 /* Frameworks */, 138 | 07DB81D8149E719700D857A9 /* Resources */, 139 | ); 140 | buildRules = ( 141 | ); 142 | dependencies = ( 143 | ); 144 | name = RKLayoutExample; 145 | productName = RKLayoutExample; 146 | productReference = 07DB81DA149E719700D857A9 /* RKLayoutExample.app */; 147 | productType = "com.apple.product-type.application"; 148 | }; 149 | /* End PBXNativeTarget section */ 150 | 151 | /* Begin PBXProject section */ 152 | 07DB81D1149E719700D857A9 /* Project object */ = { 153 | isa = PBXProject; 154 | attributes = { 155 | LastUpgradeCheck = 0420; 156 | }; 157 | buildConfigurationList = 07DB81D4149E719700D857A9 /* Build configuration list for PBXProject "RKLayoutExample" */; 158 | compatibilityVersion = "Xcode 3.2"; 159 | developmentRegion = English; 160 | hasScannedForEncodings = 0; 161 | knownRegions = ( 162 | en, 163 | ); 164 | mainGroup = 07DB81CF149E719700D857A9; 165 | productRefGroup = 07DB81DB149E719700D857A9 /* Products */; 166 | projectDirPath = ""; 167 | projectRoot = ""; 168 | targets = ( 169 | 07DB81D9149E719700D857A9 /* RKLayoutExample */, 170 | ); 171 | }; 172 | /* End PBXProject section */ 173 | 174 | /* Begin PBXResourcesBuildPhase section */ 175 | 07DB81D8149E719700D857A9 /* Resources */ = { 176 | isa = PBXResourcesBuildPhase; 177 | buildActionMask = 2147483647; 178 | files = ( 179 | 07DB81E9149E719700D857A9 /* InfoPlist.strings in Resources */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | /* End PBXResourcesBuildPhase section */ 184 | 185 | /* Begin PBXSourcesBuildPhase section */ 186 | 07DB81D6149E719700D857A9 /* Sources */ = { 187 | isa = PBXSourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | 07DB81EB149E719700D857A9 /* main.m in Sources */, 191 | 07DB81EF149E719700D857A9 /* RKAppDelegate.m in Sources */, 192 | 07DB81F2149E719700D857A9 /* RKViewController.m in Sources */, 193 | 07DB8206149E78CB00D857A9 /* RKLayout.m in Sources */, 194 | 07DB8207149E78CB00D857A9 /* UIView+RKLayoutUtil.m in Sources */, 195 | 07DB820A149F3DE200D857A9 /* RKSpacer.m in Sources */, 196 | 07CEBF5C149F7460004A947E /* RKFrameAdjustBlockManager.m in Sources */, 197 | ); 198 | runOnlyForDeploymentPostprocessing = 0; 199 | }; 200 | /* End PBXSourcesBuildPhase section */ 201 | 202 | /* Begin PBXVariantGroup section */ 203 | 07DB81E7149E719700D857A9 /* InfoPlist.strings */ = { 204 | isa = PBXVariantGroup; 205 | children = ( 206 | 07DB81E8149E719700D857A9 /* en */, 207 | ); 208 | name = InfoPlist.strings; 209 | sourceTree = ""; 210 | }; 211 | /* End PBXVariantGroup section */ 212 | 213 | /* Begin XCBuildConfiguration section */ 214 | 07DB81F9149E719700D857A9 /* Debug */ = { 215 | isa = XCBuildConfiguration; 216 | buildSettings = { 217 | ALWAYS_SEARCH_USER_PATHS = NO; 218 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 219 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 220 | COPY_PHASE_STRIP = NO; 221 | GCC_C_LANGUAGE_STANDARD = gnu99; 222 | GCC_DYNAMIC_NO_PIC = NO; 223 | GCC_OPTIMIZATION_LEVEL = 0; 224 | GCC_PREPROCESSOR_DEFINITIONS = ( 225 | "DEBUG=1", 226 | "$(inherited)", 227 | ); 228 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 229 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 230 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 231 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 232 | GCC_WARN_UNUSED_VARIABLE = YES; 233 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 234 | SDKROOT = iphoneos; 235 | TARGETED_DEVICE_FAMILY = "1,2"; 236 | }; 237 | name = Debug; 238 | }; 239 | 07DB81FA149E719700D857A9 /* Release */ = { 240 | isa = XCBuildConfiguration; 241 | buildSettings = { 242 | ALWAYS_SEARCH_USER_PATHS = NO; 243 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 244 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 245 | COPY_PHASE_STRIP = YES; 246 | GCC_C_LANGUAGE_STANDARD = gnu99; 247 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 248 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 249 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 250 | GCC_WARN_UNUSED_VARIABLE = YES; 251 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 252 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 253 | SDKROOT = iphoneos; 254 | TARGETED_DEVICE_FAMILY = "1,2"; 255 | VALIDATE_PRODUCT = YES; 256 | }; 257 | name = Release; 258 | }; 259 | 07DB81FC149E719700D857A9 /* Debug */ = { 260 | isa = XCBuildConfiguration; 261 | buildSettings = { 262 | ALWAYS_SEARCH_USER_PATHS = NO; 263 | CLANG_ENABLE_OBJC_ARC = YES; 264 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 265 | GCC_PREFIX_HEADER = "RKLayoutExample/RKLayoutExample-Prefix.pch"; 266 | INFOPLIST_FILE = "RKLayoutExample/RKLayoutExample-Info.plist"; 267 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 268 | PRODUCT_NAME = "$(TARGET_NAME)"; 269 | WRAPPER_EXTENSION = app; 270 | }; 271 | name = Debug; 272 | }; 273 | 07DB81FD149E719700D857A9 /* Release */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_ENABLE_OBJC_ARC = YES; 278 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 279 | GCC_PREFIX_HEADER = "RKLayoutExample/RKLayoutExample-Prefix.pch"; 280 | INFOPLIST_FILE = "RKLayoutExample/RKLayoutExample-Info.plist"; 281 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 282 | PRODUCT_NAME = "$(TARGET_NAME)"; 283 | WRAPPER_EXTENSION = app; 284 | }; 285 | name = Release; 286 | }; 287 | /* End XCBuildConfiguration section */ 288 | 289 | /* Begin XCConfigurationList section */ 290 | 07DB81D4149E719700D857A9 /* Build configuration list for PBXProject "RKLayoutExample" */ = { 291 | isa = XCConfigurationList; 292 | buildConfigurations = ( 293 | 07DB81F9149E719700D857A9 /* Debug */, 294 | 07DB81FA149E719700D857A9 /* Release */, 295 | ); 296 | defaultConfigurationIsVisible = 0; 297 | defaultConfigurationName = Release; 298 | }; 299 | 07DB81FB149E719700D857A9 /* Build configuration list for PBXNativeTarget "RKLayoutExample" */ = { 300 | isa = XCConfigurationList; 301 | buildConfigurations = ( 302 | 07DB81FC149E719700D857A9 /* Debug */, 303 | 07DB81FD149E719700D857A9 /* Release */, 304 | ); 305 | defaultConfigurationIsVisible = 0; 306 | defaultConfigurationName = Release; 307 | }; 308 | /* End XCConfigurationList section */ 309 | }; 310 | rootObject = 07DB81D1149E719700D857A9 /* Project object */; 311 | } 312 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample.xcodeproj/project.xcworkspace/xcuserdata/rkovacevic.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rkovacevic/RKLayout/6cd65005564ce207ff5ebf129970c4650b99fe48/RKLayoutExample/RKLayoutExample.xcodeproj/project.xcworkspace/xcuserdata/rkovacevic.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample.xcodeproj/project.xcworkspace/xcuserdata/rkovacevic.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceUserSettings_HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | IDEWorkspaceUserSettings_SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample.xcodeproj/xcuserdata/rkovacevic.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample.xcodeproj/xcuserdata/rkovacevic.xcuserdatad/xcschemes/RKLayoutExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 38 | 39 | 40 | 41 | 49 | 50 | 56 | 57 | 58 | 59 | 60 | 61 | 67 | 68 | 74 | 75 | 76 | 77 | 79 | 80 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample.xcodeproj/xcuserdata/rkovacevic.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | RKLayoutExample.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 07DB81D9149E719700D857A9 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample/RKAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // RKAppDelegate.h 3 | // RKLayoutExample 4 | // 5 | // Created by Robert Kovačević on 12/18/11. 6 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class RKViewController; 12 | 13 | @interface RKAppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @property (strong, nonatomic) RKViewController *viewController; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample/RKAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // RKAppDelegate.m 3 | // RKLayoutExample 4 | // 5 | // Created by Robert Kovačević on 12/18/11. 6 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 7 | // 8 | 9 | #import "RKAppDelegate.h" 10 | 11 | #import "RKViewController.h" 12 | 13 | @implementation RKAppDelegate 14 | 15 | @synthesize window = _window; 16 | @synthesize viewController = _viewController; 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 19 | { 20 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 21 | self.viewController = [[RKViewController alloc] init]; 22 | self.window.rootViewController = self.viewController; 23 | [self.window makeKeyAndVisible]; 24 | return YES; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample/RKLayoutExample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFiles 12 | 13 | CFBundleIdentifier 14 | com.rkovacevic.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample/RKLayoutExample-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'RKLayoutExample' target in the 'RKLayoutExample' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | 16 | #define RANDOM_FLOAT(smallNumber, bigNumber) ((((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * (bigNumber - smallNumber)) + smallNumber) -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample/RKViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RKViewController.h 3 | // RKLayoutExample 4 | // 5 | // Created by Robert Kovačević on 12/18/11. 6 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class RKLayout; 12 | 13 | @interface RKViewController : UIViewController { 14 | RKLayout* _controlsLayout; 15 | RKLayout* _mainLayout; 16 | UISegmentedControl* _horizontalAlignModeSegmentedControl; 17 | UISegmentedControl* _verticalAlignModeSegmentedControl; 18 | UISegmentedControl* _spacingModeSegmentedControl; 19 | UISegmentedControl* _layoutModeSegmentedControl; 20 | UIButton* _addSubviewButton; 21 | UIButton* _removeSubviewButton; 22 | 23 | RKLayout* _layoutDemoView; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample/RKViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RKViewController.m 3 | // RKLayoutExample 4 | // 5 | // Created by Robert Kovačević on 12/18/11. 6 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 7 | // 8 | 9 | #import "RKViewController.h" 10 | #import "RKLayout.h" 11 | 12 | @interface RKViewController () 13 | 14 | - (void)layoutViews; 15 | 16 | @end 17 | 18 | @implementation RKViewController 19 | 20 | #pragma mark - View lifecycle 21 | 22 | - (void)loadView 23 | { 24 | [super loadView]; 25 | 26 | NSArray *layoutModes = [NSArray arrayWithObjects: @"Horizontal", @"Vertical", @"Grid", nil]; 27 | NSArray *spacingModes = [NSArray arrayWithObjects: @"Fixed spacing", @"Auto spacing", nil]; 28 | NSArray *horizontalAlignModes = [NSArray arrayWithObjects: @"Left", @"Center", @"Right", nil]; 29 | NSArray *verticalAlignModes = [NSArray arrayWithObjects: @"Top", @"Center", @"Bottom", nil]; 30 | 31 | _mainLayout = [[RKLayout alloc] initWithFrame:self.view.bounds withMode:RKLayoutModeVertical]; 32 | _mainLayout.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 33 | _mainLayout.horizontalAlign = RKLayoutHorizontalAlignCenter; 34 | _mainLayout.backgroundColor = [UIColor whiteColor]; 35 | [self.view addSubview:_mainLayout]; 36 | 37 | _controlsLayout = [[RKLayout alloc] initWithFrame:RKOriginRectMake(300.0f, 155.0f) withMode:RKLayoutModeVertical withSpacing:5.0f]; 38 | [_mainLayout addSubview:_controlsLayout]; 39 | 40 | _horizontalAlignModeSegmentedControl = [[UISegmentedControl alloc] initWithItems:horizontalAlignModes]; 41 | _horizontalAlignModeSegmentedControl.frame = RKOriginRectMake(300, 25); 42 | _horizontalAlignModeSegmentedControl.segmentedControlStyle = UISegmentedControlStylePlain; 43 | _horizontalAlignModeSegmentedControl.selectedSegmentIndex = 1; 44 | [_horizontalAlignModeSegmentedControl addTarget:self action:@selector(horizontalAlignModeSelected:) forControlEvents:UIControlEventValueChanged]; 45 | 46 | [_controlsLayout addSubview:_horizontalAlignModeSegmentedControl]; 47 | 48 | _verticalAlignModeSegmentedControl = [[UISegmentedControl alloc] initWithItems:verticalAlignModes]; 49 | _verticalAlignModeSegmentedControl.frame = RKOriginRectMake(300, 25); 50 | _verticalAlignModeSegmentedControl.segmentedControlStyle = UISegmentedControlStylePlain; 51 | _verticalAlignModeSegmentedControl.selectedSegmentIndex = 1; 52 | [_verticalAlignModeSegmentedControl addTarget:self action:@selector(verticalAlignModeSelected:) forControlEvents:UIControlEventValueChanged]; 53 | 54 | [_controlsLayout addSubview:_verticalAlignModeSegmentedControl]; 55 | 56 | _layoutModeSegmentedControl = [[UISegmentedControl alloc] initWithItems:layoutModes]; 57 | _layoutModeSegmentedControl.frame = RKOriginRectMake(300, 25); 58 | _layoutModeSegmentedControl.segmentedControlStyle = UISegmentedControlStylePlain; 59 | _layoutModeSegmentedControl.selectedSegmentIndex = 0; 60 | [_layoutModeSegmentedControl addTarget:self action:@selector(layoutModeSelected:) forControlEvents:UIControlEventValueChanged]; 61 | 62 | [_controlsLayout addSubview:_layoutModeSegmentedControl]; 63 | 64 | UISegmentedControl* spacingSegmentedControl = [[UISegmentedControl alloc] initWithItems:spacingModes]; 65 | spacingSegmentedControl.frame = RKOriginRectMake(300, 25); 66 | spacingSegmentedControl.segmentedControlStyle = UISegmentedControlStylePlain; 67 | spacingSegmentedControl.selectedSegmentIndex = 0; 68 | [spacingSegmentedControl addTarget:self action:@selector(spacingModeSelected:) forControlEvents:UIControlEventValueChanged]; 69 | 70 | [_controlsLayout addSubview:spacingSegmentedControl]; 71 | 72 | RKLayout* buttonsLayout = [[RKLayout alloc] initWithFrame:RKOriginRectMake(300, 25) withMode:RKLayoutModeHorizontal withSpacing:5.0f]; 73 | buttonsLayout.horizontalAlign = RKLayoutHorizontalAlignCenter; 74 | [_controlsLayout addSubview:buttonsLayout]; 75 | 76 | _addSubviewButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 77 | _addSubviewButton.frame = RKOriginRectMake(120, 25); 78 | [_addSubviewButton setTitle:@"Add subview" forState:UIControlStateNormal]; 79 | [_addSubviewButton addTarget:self action:@selector(addSubviewButtonTapped) forControlEvents:UIControlEventTouchUpInside]; 80 | [buttonsLayout addSubview:_addSubviewButton]; 81 | 82 | _removeSubviewButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 83 | _removeSubviewButton.frame = RKOriginRectMake(140, 25); 84 | [_removeSubviewButton setTitle:@"Remove subview" forState:UIControlStateNormal]; 85 | [_removeSubviewButton addTarget:self action:@selector(removeSubviewButtonTapped) forControlEvents:UIControlEventTouchUpInside]; 86 | [buttonsLayout addSubview:_removeSubviewButton]; 87 | 88 | _layoutDemoView = [[RKLayout alloc] initWithFrame:CGRectZero withMode:RKLayoutModeHorizontal withSpacing:10.0f]; 89 | _layoutDemoView.horizontalAlign = RKLayoutHorizontalAlignCenter; 90 | _layoutDemoView.verticalAlign = RKLayoutVerticalAlignCenter; 91 | _layoutDemoView.spacingMode = RKLayoutSpacingModeFixed; 92 | _layoutDemoView.backgroundColor = [UIColor yellowColor]; 93 | 94 | for (int i = 0; i < 10; i++) 95 | { 96 | UIView* test = [[UIView alloc] initWithFrame:CGRectMake(0, 0, RANDOM_FLOAT(10, 100), RANDOM_FLOAT(10, 100))]; 97 | test.backgroundColor = [UIColor redColor]; 98 | [_layoutDemoView addSubview:test]; 99 | } 100 | 101 | [_mainLayout addSubview:_layoutDemoView]; 102 | 103 | [self layoutViews]; 104 | } 105 | 106 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 107 | { 108 | [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; 109 | 110 | [self layoutViews]; 111 | } 112 | 113 | #pragma mark - Private 114 | 115 | - (void)layoutViews 116 | { 117 | _layoutDemoView.frame = RKOriginRectMake(self.view.bounds.size.width, self.view.bounds.size.height - _controlsLayout.frame.size.height); 118 | 119 | [self.view setNeedsLayout]; 120 | } 121 | 122 | - (void)addSubviewButtonTapped 123 | { 124 | [UIView beginAnimations:nil context:NULL]; 125 | [UIView setAnimationDuration:0.5]; 126 | [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; 127 | 128 | UIView* test = [[UIView alloc] initWithFrame:CGRectMake(0, 0, RANDOM_FLOAT(10, 100), RANDOM_FLOAT(10, 100))]; 129 | test.backgroundColor = [UIColor redColor]; 130 | [_layoutDemoView addSubview:test]; 131 | 132 | [_layoutDemoView layoutIfNeeded]; 133 | [UIView commitAnimations]; 134 | } 135 | 136 | - (void)removeSubviewButtonTapped 137 | { 138 | if (_layoutDemoView.subviews.count <= 0) return; 139 | 140 | [UIView beginAnimations:nil context:NULL]; 141 | [UIView setAnimationDuration:0.5]; 142 | [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; 143 | 144 | [[_layoutDemoView.subviews objectAtIndex:(_layoutDemoView.subviews.count - 1)] removeFromSuperview]; 145 | 146 | [_layoutDemoView layoutIfNeeded]; 147 | [UIView commitAnimations]; 148 | } 149 | 150 | 151 | - (void)layoutModeSelected:(id)sender 152 | { 153 | UISegmentedControl *segmentedControl = (UISegmentedControl *)sender; 154 | 155 | [UIView beginAnimations:nil context:NULL]; 156 | [UIView setAnimationDuration:0.5]; 157 | [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; 158 | 159 | switch (segmentedControl.selectedSegmentIndex) 160 | { 161 | case 0: 162 | _layoutDemoView.layoutMode = RKLayoutModeHorizontal; 163 | break; 164 | case 1: 165 | _layoutDemoView.layoutMode = RKLayoutModeVertical; 166 | break; 167 | default: 168 | _layoutDemoView.layoutMode = RKLayoutModeGrid; 169 | break; 170 | } 171 | [_layoutDemoView layoutIfNeeded]; 172 | [UIView commitAnimations]; 173 | } 174 | 175 | - (void)horizontalAlignModeSelected:(id)sender 176 | { 177 | UISegmentedControl *segmentedControl = (UISegmentedControl *)sender; 178 | 179 | [UIView beginAnimations:nil context:NULL]; 180 | [UIView setAnimationDuration:0.5]; 181 | [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; 182 | 183 | switch (segmentedControl.selectedSegmentIndex) 184 | { 185 | case 0: 186 | _layoutDemoView.horizontalAlign = RKLayoutHorizontalAlignLeft; 187 | break; 188 | case 1: 189 | _layoutDemoView.horizontalAlign = RKLayoutHorizontalAlignCenter; 190 | break; 191 | default: 192 | _layoutDemoView.horizontalAlign = RKLayoutHorizontalAlignRight; 193 | break; 194 | } 195 | [_layoutDemoView layoutIfNeeded]; 196 | [UIView commitAnimations]; 197 | } 198 | 199 | - (void)verticalAlignModeSelected:(id)sender 200 | { 201 | UISegmentedControl *segmentedControl = (UISegmentedControl *)sender; 202 | 203 | [UIView beginAnimations:nil context:NULL]; 204 | [UIView setAnimationDuration:0.5]; 205 | [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; 206 | 207 | switch (segmentedControl.selectedSegmentIndex) 208 | { 209 | case 0: 210 | _layoutDemoView.verticalAlign = RKLayoutVerticalAlignTop; 211 | break; 212 | case 1: 213 | _layoutDemoView.verticalAlign = RKLayoutVerticalAlignCenter; 214 | break; 215 | default: 216 | _layoutDemoView.verticalAlign = RKLayoutVerticalAlignBottom; 217 | break; 218 | } 219 | [_layoutDemoView layoutIfNeeded]; 220 | [UIView commitAnimations]; 221 | } 222 | 223 | - (void)spacingModeSelected:(id)sender 224 | { 225 | UISegmentedControl *segmentedControl = (UISegmentedControl *)sender; 226 | 227 | [UIView beginAnimations:nil context:NULL]; 228 | [UIView setAnimationDuration:0.5]; 229 | [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; 230 | 231 | switch (segmentedControl.selectedSegmentIndex) 232 | { 233 | case 0: 234 | _layoutDemoView.spacingMode = RKLayoutSpacingModeFixed; 235 | break; 236 | default: 237 | _layoutDemoView.spacingMode = RKLayoutSpacingModeAuto; 238 | } 239 | [_layoutDemoView layoutIfNeeded]; 240 | [UIView commitAnimations]; 241 | } 242 | 243 | @end 244 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /RKLayoutExample/RKLayoutExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // RKLayoutExample 4 | // 5 | // Created by Robert Kovačević on 12/18/11. 6 | // Copyright (c) 2011 Robert Kovačević. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "RKAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([RKAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Readme.textile: -------------------------------------------------------------------------------- 1 | h1. RKLayout 2 | 3 | Simple layout manager for iOS. 4 | 5 | h2. How to add to your project 6 | 7 | To use, just drag the _RKLayout_ directory to your XCode project. 8 | 9 | h2. Features 10 | 11 | * Stack views horizontally, vertically or in a grid 12 | * Set constant spacing between views, or stretch the spacing, so that the whole container view is filled 13 | * Align views relative to container (top, bottom, center, left, right, and all combinations) 14 | * Animations are supported for all properties 15 | 16 | h2. Usage 17 | 18 | See _RKLayoutExample_ project for usage. 19 | 20 | *Basic idea:* You create an istance of _RKLayout_, set _mode_ (horizontal, vertical or grid), and add subviews to it. Subview positions will then automatically be adjusted according to the selected _mode_. Note that subview size will never be changed by the layout manager. 21 | --------------------------------------------------------------------------------