├── 5.png ├── 6.png ├── 6p.png ├── Karl ├── KLBaseLayoutCalculator.h ├── KLBaseLayoutCalculator.m ├── KLHorizontalLayoutCalculator.h ├── KLHorizontalLayoutCalculator.m ├── KLLayout.h ├── KLLayoutElement+ForEngine.h ├── KLLayoutElement.h ├── KLLayoutElement.m ├── KLLayoutElementMaker.h ├── KLLayoutElementMaker.m ├── KLLayoutEngine.h ├── KLLayoutEngine.m ├── KLVerticalLayoutCalculator.h ├── KLVerticalLayoutCalculator.m ├── View+KLLayout.h └── View+KLLayout.m ├── KarlLayout.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── KarlLayout ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── first.imageset │ │ ├── Contents.json │ │ └── first.pdf │ └── second.imageset │ │ ├── Contents.json │ │ └── second.pdf ├── Base.lproj │ └── LaunchScreen.storyboard ├── FirstViewController.h ├── FirstViewController.m ├── Info.plist ├── Main.storyboard ├── SecondViewController.h ├── SecondViewController.m ├── karl.jpeg └── main.m └── README.md /5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fx91/KarlLayout/2e714abcae81a6ce9201cfbe00dc256800c4b098/5.png -------------------------------------------------------------------------------- /6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fx91/KarlLayout/2e714abcae81a6ce9201cfbe00dc256800c4b098/6.png -------------------------------------------------------------------------------- /6p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fx91/KarlLayout/2e714abcae81a6ce9201cfbe00dc256800c4b098/6p.png -------------------------------------------------------------------------------- /Karl/KLBaseLayoutCalculator.h: -------------------------------------------------------------------------------- 1 | // 2 | // KLBaseLayoutCalculator.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/16. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef struct { 13 | CGFloat offset; 14 | CGFloat length; 15 | } KLLayoutBaseLine; 16 | 17 | static inline CGFloat KLLengthMake(CGFloat originLength,CGFloat multipliedBy, CGFloat offset) 18 | { 19 | return multipliedBy * originLength + offset; 20 | } 21 | 22 | @interface KLBaseLayoutCalculator : NSObject 23 | 24 | + (instancetype)calculator; 25 | 26 | - (KLLayoutBaseLine)baseLineWithLayoutElements:(NSArray *)elements view:(UIView *)view; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Karl/KLBaseLayoutCalculator.m: -------------------------------------------------------------------------------- 1 | // 2 | // KLBaseLayoutCalculator.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/16. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "KLBaseLayoutCalculator.h" 10 | 11 | @implementation KLBaseLayoutCalculator 12 | 13 | + (instancetype)calculator 14 | { 15 | return [[self alloc] init]; 16 | } 17 | 18 | - (KLLayoutBaseLine)baseLineWithLayoutElements:(NSArray *)elements view:(UIView *)view 19 | { 20 | return (KLLayoutBaseLine){0,0}; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Karl/KLHorizontalLayoutCalculator.h: -------------------------------------------------------------------------------- 1 | // 2 | // KLHorizontalLayoutCalculator.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/16. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "KLBaseLayoutCalculator.h" 10 | 11 | @interface KLHorizontalLayoutCalculator : KLBaseLayoutCalculator 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Karl/KLHorizontalLayoutCalculator.m: -------------------------------------------------------------------------------- 1 | // 2 | // KLHorizontalLayoutCalculator.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/16. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "KLHorizontalLayoutCalculator.h" 10 | #import "KLLayoutElement.h" 11 | #import "KLLayoutElement+ForEngine.h" 12 | 13 | @implementation KLHorizontalLayoutCalculator 14 | 15 | - (KLLayoutBaseLine)baseLineWithLayoutElements:(NSArray *)elements view:(UIView *)view 16 | { 17 | KLLayoutBaseLine baseLine = (KLLayoutBaseLine){view.frame.origin.x, view.frame.size.width}; 18 | 19 | if (elements.count == 0) { 20 | return baseLine; 21 | } 22 | 23 | KLLayoutElement *neededLastElement; 24 | 25 | //倒序遍历 26 | for (NSUInteger i = elements.count; i > 0; i--) { 27 | KLLayoutElement *element = [elements objectAtIndex:i - 1]; 28 | switch (element.type) { 29 | case KLLayoutElementTypeLeft: { 30 | if (neededLastElement) { 31 | if (neededLastElement.type == KLLayoutElementTypeRight) { 32 | baseLine.offset = [self lengthForElement:element view:view]; 33 | baseLine.length = [self superViewWidthForView:view] - [self lengthForElement:element view:view] - [self lengthForElement:neededLastElement view:view]; 34 | return baseLine; 35 | } 36 | if (neededLastElement.type == KLLayoutElementTypeWidth) { 37 | baseLine.offset = [self lengthForElement:element view:view]; 38 | baseLine.length = [self lengthForElement:neededLastElement view:view]; 39 | return baseLine; 40 | } 41 | } 42 | else{ 43 | neededLastElement = element; 44 | } 45 | break; 46 | } 47 | case KLLayoutElementTypeRight: { 48 | if (neededLastElement) { 49 | if (neededLastElement.type == KLLayoutElementTypeLeft) { 50 | baseLine.offset = [self lengthForElement:neededLastElement view:view]; 51 | baseLine.length = [self superViewWidthForView:view] - [self lengthForElement:element view:view] - [self lengthForElement:neededLastElement view:view]; 52 | return baseLine; 53 | } 54 | if (neededLastElement.type == KLLayoutElementTypeWidth) { 55 | baseLine.offset = [self superViewWidthForView:view] - [self lengthForElement:neededLastElement view:view] - [self lengthForElement:element view:view]; 56 | baseLine.length = [self lengthForElement:neededLastElement view:view]; 57 | return baseLine; 58 | } 59 | } 60 | else{ 61 | neededLastElement = element; 62 | } 63 | break; 64 | } 65 | case KLLayoutElementTypeWidth: { 66 | if (neededLastElement) { 67 | if (neededLastElement.type == KLLayoutElementTypeLeft) { 68 | baseLine.offset = [self lengthForElement:neededLastElement view:view]; 69 | baseLine.length = [self lengthForElement:element view:view]; 70 | return baseLine; 71 | } 72 | if (neededLastElement.type == KLLayoutElementTypeRight) { 73 | baseLine.offset = [self superViewWidthForView:view] - [self lengthForElement:element view:view] - [self lengthForElement:neededLastElement view:view]; 74 | baseLine.length = [self lengthForElement:element view:view]; 75 | return baseLine; 76 | } 77 | } 78 | else{ 79 | neededLastElement = element; 80 | } 81 | break; 82 | } 83 | default: { 84 | break; 85 | } 86 | } 87 | } 88 | 89 | return baseLine; 90 | } 91 | 92 | - (CGFloat)superViewWidthForView:(UIView *)view 93 | { 94 | return view.superview.frame.size.width; 95 | } 96 | 97 | - (CGFloat)lengthForElement:(KLLayoutElement *)element view:(UIView *)view 98 | { 99 | return KLLengthMake([self superViewWidthForView:view], element.layoutMultipliedBy, element.layoutOffset); 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /Karl/KLLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // KLLayout.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/18. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "View+KLLayout.h" 10 | #import "KLLayoutEngine.h" 11 | -------------------------------------------------------------------------------- /Karl/KLLayoutElement+ForEngine.h: -------------------------------------------------------------------------------- 1 | // 2 | // KLLayoutElement+ForEngine.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/9. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #ifndef KLLayoutElement_ForEngine_h 10 | #define KLLayoutElement_ForEngine_h 11 | 12 | @interface KLLayoutElement (ForEngine) 13 | 14 | @property (nonatomic, readonly) CGFloat layoutOffset; 15 | 16 | @property (nonatomic, readonly) CGFloat layoutMultipliedBy; 17 | 18 | @property (nonatomic, readonly) BOOL layoutFlexible; 19 | 20 | @end 21 | 22 | #endif /* KLLayoutElement_Private_h */ 23 | 24 | -------------------------------------------------------------------------------- /Karl/KLLayoutElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // KLLayoutElement.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/4. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, KLLayoutElementType) { 12 | KLLayoutElementTypeTop = 0, 13 | KLLayoutElementTypeBottom, 14 | KLLayoutElementTypeLeft, 15 | KLLayoutElementTypeRight, 16 | KLLayoutElementTypeWidth, 17 | KLLayoutElementTypeHeight 18 | 19 | }; 20 | 21 | @interface KLLayoutElement : NSObject 22 | 23 | - (instancetype)initWithType:(KLLayoutElementType)type; 24 | 25 | - (KLLayoutElement * (^)(CGFloat offset))offset; 26 | 27 | - (KLLayoutElement * (^)(CGFloat multipliedBy))multipliedBy; 28 | 29 | - (KLLayoutElement * (^)(BOOL flexible))flexible; 30 | 31 | - (void)installForView:(UIView *)view; 32 | 33 | @property (nonatomic, readonly) KLLayoutElementType type; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Karl/KLLayoutElement.m: -------------------------------------------------------------------------------- 1 | // 2 | // KLLayoutElement.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/4. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "KLLayoutElement.h" 10 | #import "KLLayoutEngine.h" 11 | #import "KLLayoutElement+ForEngine.h" 12 | 13 | @interface KLLayoutElement () 14 | 15 | @property (nonatomic, strong) NSMutableSet *installedPolicies; 16 | 17 | @property (nonatomic, readwrite) KLLayoutElementType type; 18 | 19 | @property (nonatomic) CGFloat layoutOffset; 20 | 21 | @property (nonatomic) CGFloat layoutMultipliedBy; 22 | 23 | @property (nonatomic) BOOL layoutFlexible; 24 | 25 | @end 26 | 27 | @implementation KLLayoutElement 28 | 29 | - (instancetype)initWithType:(KLLayoutElementType)type 30 | { 31 | self = [self init]; 32 | if (!self) { 33 | return nil; 34 | } 35 | 36 | _type = type; 37 | 38 | return self; 39 | } 40 | 41 | - (KLLayoutElement * (^)(CGFloat))offset 42 | { 43 | return ^id(CGFloat offset){ 44 | self.offset = offset; 45 | return self; 46 | }; 47 | } 48 | 49 | - (KLLayoutElement * (^)(CGFloat))multipliedBy 50 | { 51 | return ^id(CGFloat multipliedBy){ 52 | self.multipliedBy = multipliedBy; 53 | return self; 54 | }; 55 | } 56 | 57 | - (KLLayoutElement * (^)(BOOL flexible))flexible 58 | { 59 | return ^id(BOOL flexible){ 60 | self.flexible = flexible; 61 | return self; 62 | }; 63 | } 64 | 65 | - (void)setFlexible:(BOOL)flexible 66 | { 67 | self.layoutFlexible = flexible; 68 | } 69 | 70 | - (void)setOffset:(CGFloat)offset 71 | { 72 | self.layoutOffset = offset; 73 | } 74 | 75 | - (void)setMultipliedBy:(CGFloat)multipliedBy 76 | { 77 | self.layoutMultipliedBy = multipliedBy; 78 | } 79 | 80 | - (void)installForView:(UIView *)view 81 | { 82 | [[KLLayoutEngine sharedEngine] registerLayoutElement:self forView:view]; 83 | } 84 | 85 | - (void)uninstall 86 | { 87 | 88 | } 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /Karl/KLLayoutElementMaker.h: -------------------------------------------------------------------------------- 1 | // 2 | // KLLayoutElementMaker.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/4. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "KLLayoutElement.h" 11 | 12 | @interface KLLayoutElementMaker : NSObject 13 | 14 | //默认相对于父视图 15 | @property (nonatomic, strong, readonly) KLLayoutElement *top; 16 | @property (nonatomic, strong, readonly) KLLayoutElement *bottom; 17 | @property (nonatomic, strong, readonly) KLLayoutElement *left; 18 | @property (nonatomic, strong, readonly) KLLayoutElement *right; 19 | @property (nonatomic, strong, readonly) KLLayoutElement *width; 20 | @property (nonatomic, strong, readonly) KLLayoutElement *height; 21 | 22 | - (NSArray *)install; 23 | 24 | - (instancetype)initWithView:(UIView *)view; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Karl/KLLayoutElementMaker.m: -------------------------------------------------------------------------------- 1 | // 2 | // KLLayoutElementMaker.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/4. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "KLLayoutElementMaker.h" 10 | 11 | @interface KLLayoutElementMaker () 12 | 13 | @property (nonatomic, weak) UIView *view; 14 | @property (nonatomic, strong) NSMutableArray *layoutElements; 15 | 16 | @end 17 | 18 | @implementation KLLayoutElementMaker 19 | 20 | - (NSArray *)install 21 | { 22 | NSArray *elements = [self.layoutElements copy]; 23 | for (KLLayoutElement *element in elements) { 24 | [element installForView:self.view]; 25 | } 26 | 27 | [self.layoutElements removeAllObjects]; 28 | 29 | return elements; 30 | } 31 | 32 | - (instancetype)initWithView:(UIView *)view 33 | { 34 | self = [super init]; 35 | if (!self) { 36 | return nil; 37 | } 38 | 39 | _view = view; 40 | _layoutElements = [NSMutableArray array]; 41 | 42 | return self; 43 | } 44 | 45 | - (KLLayoutElement *)addElementWithType:(KLLayoutElementType)type 46 | { 47 | KLLayoutElement *element = [[KLLayoutElement alloc] initWithType:type]; 48 | [self.layoutElements addObject:element]; 49 | 50 | return element; 51 | } 52 | 53 | - (KLLayoutElement *)top 54 | { 55 | return [self addElementWithType:KLLayoutElementTypeTop]; 56 | } 57 | 58 | - (KLLayoutElement *)bottom 59 | { 60 | return [self addElementWithType:KLLayoutElementTypeBottom]; 61 | } 62 | 63 | - (KLLayoutElement *)left 64 | { 65 | return [self addElementWithType:KLLayoutElementTypeLeft]; 66 | } 67 | 68 | - (KLLayoutElement *)right 69 | { 70 | return [self addElementWithType:KLLayoutElementTypeRight]; 71 | } 72 | 73 | - (KLLayoutElement *)width 74 | { 75 | return [self addElementWithType:KLLayoutElementTypeWidth]; 76 | } 77 | 78 | - (KLLayoutElement *)height 79 | { 80 | return [self addElementWithType:KLLayoutElementTypeHeight]; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /Karl/KLLayoutEngine.h: -------------------------------------------------------------------------------- 1 | // 2 | // KLLayoutEngine.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/5. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "KLLayoutElement.h" 11 | 12 | @interface KLLayoutEngine : NSObject 13 | 14 | //调试模式 15 | - (void)setDebugModeEnable:(BOOL)enable; 16 | 17 | + (instancetype)sharedEngine; 18 | 19 | - (void)registerLayoutElement:(KLLayoutElement *)layoutElement forView:(UIView *)view; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Karl/KLLayoutEngine.m: -------------------------------------------------------------------------------- 1 | // 2 | // KLLayoutEngine.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/5. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "KLLayoutEngine.h" 10 | #import "KLLayoutElement+ForEngine.h" 11 | #import "KLHorizontalLayoutCalculator.h" 12 | #import "KLVerticalLayoutCalculator.h" 13 | 14 | static inline UIColor *RGB_A(NSInteger rgbValue, CGFloat alpha) { 15 | return [UIColor colorWithRed:((CGFloat)((rgbValue & 0xFF0000) >> 16))/255.0 green:((CGFloat)((rgbValue & 0xFF00) >> 8))/255.0 blue:((CGFloat)(rgbValue & 0xFF))/255.0 alpha:alpha]; 16 | }; 17 | 18 | @interface KLLayoutEngine () 19 | 20 | @property (nonatomic, strong) NSMutableDictionary *viewLayoutElementDict; 21 | 22 | @end 23 | 24 | @implementation KLLayoutEngine 25 | 26 | + (instancetype)sharedEngine 27 | { 28 | static KLLayoutEngine *sharedEngine = nil; 29 | static dispatch_once_t onceToken; 30 | dispatch_once(&onceToken, ^{ 31 | sharedEngine = [[self alloc] init]; 32 | }); 33 | 34 | return sharedEngine; 35 | } 36 | 37 | - (instancetype)init 38 | { 39 | self = [super init]; 40 | if (!self) { 41 | return nil; 42 | } 43 | 44 | _viewLayoutElementDict = [NSMutableDictionary dictionary]; 45 | 46 | return self; 47 | } 48 | 49 | - (void)registerLayoutElement:(KLLayoutElement *)layoutElement forView:(UIView *)view 50 | { 51 | KLLayoutElement *toReplaceElement; 52 | for (KLLayoutElement *element in [self elementsForView:view]){ 53 | if (element.type == layoutElement.type) { 54 | toReplaceElement = element; 55 | } 56 | } 57 | [[self elementsForView:view] removeObject:toReplaceElement]; 58 | [[self elementsForView:view] addObject:layoutElement]; 59 | 60 | [self makeLayoutElementsAvaliableForView:view]; 61 | } 62 | 63 | - (void)makeLayoutElementsAvaliableForView:(UIView *)view 64 | { 65 | CGRect frame = view.frame; 66 | 67 | NSArray *elements = [self elementsForView:view]; 68 | 69 | KLLayoutBaseLine horizontalLine = [[KLHorizontalLayoutCalculator calculator] baseLineWithLayoutElements:elements view:view]; 70 | KLLayoutBaseLine verticalLine = [[KLVerticalLayoutCalculator calculator] baseLineWithLayoutElements:elements view:view]; 71 | 72 | frame.origin.x = horizontalLine.offset; 73 | frame.origin.y = verticalLine.offset; 74 | frame.size.width = horizontalLine.length; 75 | frame.size.height = verticalLine.length; 76 | 77 | view.frame = frame; 78 | 79 | for (KLLayoutElement *element in elements) { 80 | switch (element.type) { 81 | case KLLayoutElementTypeTop: { 82 | 83 | if (element.layoutFlexible) { 84 | view.autoresizingMask = view.autoresizingMask | UIViewAutoresizingFlexibleTopMargin; 85 | }else{ 86 | view.autoresizingMask = view.autoresizingMask & (~UIViewAutoresizingFlexibleTopMargin); 87 | } 88 | 89 | break; 90 | } 91 | case KLLayoutElementTypeBottom: { 92 | 93 | if (element.layoutFlexible) { 94 | view.autoresizingMask = view.autoresizingMask | UIViewAutoresizingFlexibleBottomMargin; 95 | }else{ 96 | view.autoresizingMask = view.autoresizingMask & (~UIViewAutoresizingFlexibleBottomMargin); 97 | } 98 | 99 | break; 100 | } 101 | case KLLayoutElementTypeLeft: { 102 | 103 | if (element.layoutFlexible) { 104 | view.autoresizingMask = view.autoresizingMask | UIViewAutoresizingFlexibleLeftMargin; 105 | }else{ 106 | view.autoresizingMask = view.autoresizingMask & (~UIViewAutoresizingFlexibleLeftMargin); 107 | } 108 | 109 | break; 110 | } 111 | case KLLayoutElementTypeRight: { 112 | 113 | if (element.layoutFlexible) { 114 | view.autoresizingMask = view.autoresizingMask | UIViewAutoresizingFlexibleRightMargin; 115 | }else{ 116 | view.autoresizingMask = view.autoresizingMask & (~UIViewAutoresizingFlexibleRightMargin); 117 | } 118 | 119 | break; 120 | } 121 | case KLLayoutElementTypeWidth: { 122 | 123 | if (element.layoutFlexible) { 124 | view.autoresizingMask = view.autoresizingMask | UIViewAutoresizingFlexibleWidth; 125 | }else{ 126 | view.autoresizingMask = view.autoresizingMask & (~UIViewAutoresizingFlexibleWidth); 127 | } 128 | 129 | break; 130 | } 131 | case KLLayoutElementTypeHeight: { 132 | 133 | if (element.layoutFlexible) { 134 | view.autoresizingMask = view.autoresizingMask | UIViewAutoresizingFlexibleHeight; 135 | }else{ 136 | view.autoresizingMask = view.autoresizingMask & (~UIViewAutoresizingFlexibleHeight); 137 | } 138 | 139 | break; 140 | } 141 | } 142 | } 143 | } 144 | 145 | #pragma mark - Inner 146 | 147 | - (NSMutableArray *)elementsForView:(UIView *)view 148 | { 149 | NSMutableArray *arrayForView; 150 | 151 | if ([self.viewLayoutElementDict objectForKey:[self addressForView:view]]) { 152 | arrayForView = [self.viewLayoutElementDict objectForKey:[self addressForView:view]]; 153 | 154 | } 155 | else{ 156 | arrayForView = [NSMutableArray array]; 157 | [self.viewLayoutElementDict setObject:arrayForView forKey:[self addressForView:view]]; 158 | } 159 | 160 | return arrayForView; 161 | } 162 | 163 | - (NSString *)addressForView:(UIView *)view 164 | { 165 | NSString *address = [NSString stringWithFormat:@"%p", view]; 166 | return address; 167 | } 168 | 169 | - (UIView *)viewAtAddress:(NSString *)address 170 | { 171 | __unsafe_unretained UIView *view; 172 | sscanf([address cStringUsingEncoding:NSUTF8StringEncoding], "%p", &view); 173 | 174 | return view; 175 | } 176 | 177 | #pragma mark - Debug 178 | 179 | - (void)setDebugModeEnable:(BOOL)enable 180 | { 181 | if (enable) { 182 | for (NSString *address in [self.viewLayoutElementDict allKeys]) { 183 | UIView *view = [self viewAtAddress:address]; 184 | [self setupRandomColorWithView:view]; 185 | } 186 | } 187 | } 188 | 189 | - (void)setupRandomColorWithView:(UIView *)view 190 | { 191 | int randomIndex = rand() % [[self colorArray] count]; 192 | [view setBackgroundColor:[[self colorArray] objectAtIndex:randomIndex]]; 193 | } 194 | 195 | - (NSArray *)colorArray 196 | { 197 | return @[ 198 | RGB_A(0xF9D7C9, 1), 199 | RGB_A(0xCFC2AD, 1), 200 | RGB_A(0xC5CAE9, 1), 201 | RGB_A(0xC8E6C9, 1), 202 | RGB_A(0xFFCDD2, 1), 203 | RGB_A(0xFDEFBA, 1), 204 | RGB_A(0xF9D7C1, 1), 205 | RGB_A(0xCFC2A1, 1), 206 | RGB_A(0xC5CAE1, 1), 207 | RGB_A(0xC8E6C1, 1), 208 | RGB_A(0xFFCDD1, 1), 209 | RGB_A(0xFDEFB1, 1), 210 | 211 | ]; 212 | } 213 | 214 | @end 215 | 216 | 217 | -------------------------------------------------------------------------------- /Karl/KLVerticalLayoutCalculator.h: -------------------------------------------------------------------------------- 1 | // 2 | // KLVerticalLayoutCalculator.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/16. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "KLBaseLayoutCalculator.h" 10 | 11 | @interface KLVerticalLayoutCalculator : KLBaseLayoutCalculator 12 | 13 | 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Karl/KLVerticalLayoutCalculator.m: -------------------------------------------------------------------------------- 1 | // 2 | // KLVerticalLayoutCalculator.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/16. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "KLVerticalLayoutCalculator.h" 10 | #import "KLLayoutElement.h" 11 | #import "KLLayoutElement+ForEngine.h" 12 | 13 | @implementation KLVerticalLayoutCalculator 14 | 15 | - (KLLayoutBaseLine)baseLineWithLayoutElements:(NSArray *)elements view:(UIView *)view 16 | { 17 | KLLayoutBaseLine baseLine = (KLLayoutBaseLine){view.frame.origin.y, view.frame.size.height}; 18 | 19 | if (elements.count == 0) { 20 | return baseLine; 21 | } 22 | 23 | KLLayoutElement *neededLastElement; 24 | 25 | //倒序遍历 26 | for (NSUInteger i = elements.count; i > 0; i--) { 27 | KLLayoutElement *element = [elements objectAtIndex:i - 1]; 28 | switch (element.type) { 29 | case KLLayoutElementTypeTop: { 30 | if (neededLastElement) { 31 | if (neededLastElement.type == KLLayoutElementTypeBottom) { 32 | baseLine.offset = [self lengthForElement:element view:view]; 33 | baseLine.length = [self superViewHeightForView:view] 34 | - [self lengthForElement:element view:view] 35 | - [self lengthForElement:neededLastElement view:view]; 36 | return baseLine; 37 | } 38 | if (neededLastElement.type == KLLayoutElementTypeHeight) { 39 | baseLine.offset = [self lengthForElement:element view:view]; 40 | baseLine.length = [self lengthForElement:neededLastElement view:view]; 41 | return baseLine; 42 | } 43 | } 44 | else{ 45 | neededLastElement = element; 46 | } 47 | break; 48 | } 49 | case KLLayoutElementTypeBottom: { 50 | if (neededLastElement) { 51 | if (neededLastElement.type == KLLayoutElementTypeTop) { 52 | baseLine.offset = [self lengthForElement:neededLastElement view:view]; 53 | baseLine.length = [self superViewHeightForView:view] - [self lengthForElement:element view:view] - [self lengthForElement:neededLastElement view:view]; 54 | return baseLine; 55 | } 56 | if (neededLastElement.type == KLLayoutElementTypeHeight) { 57 | baseLine.offset = [self superViewHeightForView:view] - [self lengthForElement:neededLastElement view:view] - [self lengthForElement:element view:view]; 58 | baseLine.length = [self lengthForElement:neededLastElement view:view]; 59 | return baseLine; 60 | } 61 | } 62 | else{ 63 | neededLastElement = element; 64 | } 65 | break; 66 | } 67 | case KLLayoutElementTypeHeight: { 68 | if (neededLastElement) { 69 | if (neededLastElement.type == KLLayoutElementTypeTop) { 70 | baseLine.offset = [self lengthForElement:neededLastElement view:view]; 71 | baseLine.length = [self lengthForElement:element view:view]; 72 | return baseLine; 73 | } 74 | if (neededLastElement.type == KLLayoutElementTypeBottom) { 75 | baseLine.offset = [self superViewHeightForView:view] - [self lengthForElement:element view:view] - [self lengthForElement:neededLastElement view:view]; 76 | baseLine.length = [self lengthForElement:element view:view]; 77 | return baseLine; 78 | } 79 | } 80 | else{ 81 | neededLastElement = element; 82 | } 83 | break; 84 | } 85 | default: { 86 | break; 87 | } 88 | } 89 | } 90 | 91 | return baseLine; 92 | } 93 | 94 | - (CGFloat)superViewHeightForView:(UIView *)view 95 | { 96 | return view.superview.frame.size.height; 97 | } 98 | 99 | - (CGFloat)lengthForElement:(KLLayoutElement *)element view:(UIView *)view 100 | { 101 | return KLLengthMake([self superViewHeightForView:view], element.layoutMultipliedBy, element.layoutOffset); 102 | } 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /Karl/View+KLLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // View+KLLayout.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/4. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "KLLayoutElementMaker.h" 11 | 12 | @interface UIView (KLLayout) 13 | 14 | - (NSArray *)kl_makeLayoutElement:(void (^)(KLLayoutElementMaker *make))block; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Karl/View+KLLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // View+KLLayout.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/8/4. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "View+KLLayout.h" 10 | 11 | @implementation UIView (KLLayout) 12 | 13 | - (NSArray *)kl_makeLayoutElement:(void (^)(KLLayoutElementMaker *))block 14 | { 15 | KLLayoutElementMaker *maker = [[KLLayoutElementMaker alloc] initWithView:self]; 16 | 17 | block(maker); 18 | 19 | return [maker install]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /KarlLayout.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E724A5721D64D13E00F41683 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A5711D64D13E00F41683 /* main.m */; }; 11 | E724A57D1D64D13E00F41683 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E724A57C1D64D13E00F41683 /* Assets.xcassets */; }; 12 | E724A5801D64D13E00F41683 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E724A57E1D64D13E00F41683 /* LaunchScreen.storyboard */; }; 13 | E724A58E1D64D17400F41683 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A5881D64D17400F41683 /* AppDelegate.m */; }; 14 | E724A58F1D64D17400F41683 /* FirstViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A58A1D64D17400F41683 /* FirstViewController.m */; }; 15 | E724A5901D64D17400F41683 /* SecondViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A58C1D64D17400F41683 /* SecondViewController.m */; }; 16 | E724A5911D64D17400F41683 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E724A58D1D64D17400F41683 /* Main.storyboard */; }; 17 | E724A5AB1D64D65400F41683 /* karl.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = E724A5AA1D64D65400F41683 /* karl.jpeg */; }; 18 | E724A5BD1D64D9BB00F41683 /* KLBaseLayoutCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A5AE1D64D9BB00F41683 /* KLBaseLayoutCalculator.m */; }; 19 | E724A5BE1D64D9BB00F41683 /* KLHorizontalLayoutCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A5B01D64D9BB00F41683 /* KLHorizontalLayoutCalculator.m */; }; 20 | E724A5BF1D64D9BB00F41683 /* KLLayoutElement.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A5B31D64D9BB00F41683 /* KLLayoutElement.m */; }; 21 | E724A5C01D64D9BB00F41683 /* KLLayoutElementMaker.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A5B61D64D9BB00F41683 /* KLLayoutElementMaker.m */; }; 22 | E724A5C11D64D9BB00F41683 /* KLLayoutEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A5B81D64D9BB00F41683 /* KLLayoutEngine.m */; }; 23 | E724A5C21D64D9BB00F41683 /* KLVerticalLayoutCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A5BA1D64D9BB00F41683 /* KLVerticalLayoutCalculator.m */; }; 24 | E724A5C31D64D9BB00F41683 /* View+KLLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = E724A5BC1D64D9BB00F41683 /* View+KLLayout.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | E724A56D1D64D13E00F41683 /* KarlLayout.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KarlLayout.app; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | E724A5711D64D13E00F41683 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30 | E724A57C1D64D13E00F41683 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 31 | E724A57F1D64D13E00F41683 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 32 | E724A5811D64D13E00F41683 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | E724A5871D64D17400F41683 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 34 | E724A5881D64D17400F41683 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 35 | E724A5891D64D17400F41683 /* FirstViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FirstViewController.h; sourceTree = ""; }; 36 | E724A58A1D64D17400F41683 /* FirstViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirstViewController.m; sourceTree = ""; }; 37 | E724A58B1D64D17400F41683 /* SecondViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecondViewController.h; sourceTree = ""; }; 38 | E724A58C1D64D17400F41683 /* SecondViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecondViewController.m; sourceTree = ""; }; 39 | E724A58D1D64D17400F41683 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 40 | E724A5AA1D64D65400F41683 /* karl.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = karl.jpeg; sourceTree = ""; }; 41 | E724A5AD1D64D9BB00F41683 /* KLBaseLayoutCalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KLBaseLayoutCalculator.h; path = Karl/KLBaseLayoutCalculator.h; sourceTree = ""; }; 42 | E724A5AE1D64D9BB00F41683 /* KLBaseLayoutCalculator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KLBaseLayoutCalculator.m; path = Karl/KLBaseLayoutCalculator.m; sourceTree = ""; }; 43 | E724A5AF1D64D9BB00F41683 /* KLHorizontalLayoutCalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KLHorizontalLayoutCalculator.h; path = Karl/KLHorizontalLayoutCalculator.h; sourceTree = ""; }; 44 | E724A5B01D64D9BB00F41683 /* KLHorizontalLayoutCalculator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KLHorizontalLayoutCalculator.m; path = Karl/KLHorizontalLayoutCalculator.m; sourceTree = ""; }; 45 | E724A5B11D64D9BB00F41683 /* KLLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KLLayout.h; path = Karl/KLLayout.h; sourceTree = ""; }; 46 | E724A5B21D64D9BB00F41683 /* KLLayoutElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KLLayoutElement.h; path = Karl/KLLayoutElement.h; sourceTree = ""; }; 47 | E724A5B31D64D9BB00F41683 /* KLLayoutElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KLLayoutElement.m; path = Karl/KLLayoutElement.m; sourceTree = ""; }; 48 | E724A5B41D64D9BB00F41683 /* KLLayoutElement+ForEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "KLLayoutElement+ForEngine.h"; path = "Karl/KLLayoutElement+ForEngine.h"; sourceTree = ""; }; 49 | E724A5B51D64D9BB00F41683 /* KLLayoutElementMaker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KLLayoutElementMaker.h; path = Karl/KLLayoutElementMaker.h; sourceTree = ""; }; 50 | E724A5B61D64D9BB00F41683 /* KLLayoutElementMaker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KLLayoutElementMaker.m; path = Karl/KLLayoutElementMaker.m; sourceTree = ""; }; 51 | E724A5B71D64D9BB00F41683 /* KLLayoutEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KLLayoutEngine.h; path = Karl/KLLayoutEngine.h; sourceTree = ""; }; 52 | E724A5B81D64D9BB00F41683 /* KLLayoutEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KLLayoutEngine.m; path = Karl/KLLayoutEngine.m; sourceTree = ""; }; 53 | E724A5B91D64D9BB00F41683 /* KLVerticalLayoutCalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KLVerticalLayoutCalculator.h; path = Karl/KLVerticalLayoutCalculator.h; sourceTree = ""; }; 54 | E724A5BA1D64D9BB00F41683 /* KLVerticalLayoutCalculator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KLVerticalLayoutCalculator.m; path = Karl/KLVerticalLayoutCalculator.m; sourceTree = ""; }; 55 | E724A5BB1D64D9BB00F41683 /* View+KLLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "View+KLLayout.h"; path = "Karl/View+KLLayout.h"; sourceTree = ""; }; 56 | E724A5BC1D64D9BB00F41683 /* View+KLLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "View+KLLayout.m"; path = "Karl/View+KLLayout.m"; sourceTree = ""; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | E724A56A1D64D13E00F41683 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | E724A5641D64D13E00F41683 = { 71 | isa = PBXGroup; 72 | children = ( 73 | E724A5921D64D18100F41683 /* Karl */, 74 | E724A56F1D64D13E00F41683 /* KarlLayout */, 75 | E724A56E1D64D13E00F41683 /* Products */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | E724A56E1D64D13E00F41683 /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | E724A56D1D64D13E00F41683 /* KarlLayout.app */, 83 | ); 84 | name = Products; 85 | sourceTree = ""; 86 | }; 87 | E724A56F1D64D13E00F41683 /* KarlLayout */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | E724A5871D64D17400F41683 /* AppDelegate.h */, 91 | E724A5881D64D17400F41683 /* AppDelegate.m */, 92 | E724A5891D64D17400F41683 /* FirstViewController.h */, 93 | E724A58A1D64D17400F41683 /* FirstViewController.m */, 94 | E724A58B1D64D17400F41683 /* SecondViewController.h */, 95 | E724A58C1D64D17400F41683 /* SecondViewController.m */, 96 | E724A58D1D64D17400F41683 /* Main.storyboard */, 97 | E724A57C1D64D13E00F41683 /* Assets.xcassets */, 98 | E724A5AA1D64D65400F41683 /* karl.jpeg */, 99 | E724A57E1D64D13E00F41683 /* LaunchScreen.storyboard */, 100 | E724A5811D64D13E00F41683 /* Info.plist */, 101 | E724A5701D64D13E00F41683 /* Supporting Files */, 102 | ); 103 | path = KarlLayout; 104 | sourceTree = ""; 105 | }; 106 | E724A5701D64D13E00F41683 /* Supporting Files */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | E724A5711D64D13E00F41683 /* main.m */, 110 | ); 111 | name = "Supporting Files"; 112 | sourceTree = ""; 113 | }; 114 | E724A5921D64D18100F41683 /* Karl */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | E724A5AD1D64D9BB00F41683 /* KLBaseLayoutCalculator.h */, 118 | E724A5AE1D64D9BB00F41683 /* KLBaseLayoutCalculator.m */, 119 | E724A5AF1D64D9BB00F41683 /* KLHorizontalLayoutCalculator.h */, 120 | E724A5B01D64D9BB00F41683 /* KLHorizontalLayoutCalculator.m */, 121 | E724A5B11D64D9BB00F41683 /* KLLayout.h */, 122 | E724A5B21D64D9BB00F41683 /* KLLayoutElement.h */, 123 | E724A5B31D64D9BB00F41683 /* KLLayoutElement.m */, 124 | E724A5B41D64D9BB00F41683 /* KLLayoutElement+ForEngine.h */, 125 | E724A5B51D64D9BB00F41683 /* KLLayoutElementMaker.h */, 126 | E724A5B61D64D9BB00F41683 /* KLLayoutElementMaker.m */, 127 | E724A5B71D64D9BB00F41683 /* KLLayoutEngine.h */, 128 | E724A5B81D64D9BB00F41683 /* KLLayoutEngine.m */, 129 | E724A5B91D64D9BB00F41683 /* KLVerticalLayoutCalculator.h */, 130 | E724A5BA1D64D9BB00F41683 /* KLVerticalLayoutCalculator.m */, 131 | E724A5BB1D64D9BB00F41683 /* View+KLLayout.h */, 132 | E724A5BC1D64D9BB00F41683 /* View+KLLayout.m */, 133 | ); 134 | name = Karl; 135 | sourceTree = ""; 136 | }; 137 | /* End PBXGroup section */ 138 | 139 | /* Begin PBXNativeTarget section */ 140 | E724A56C1D64D13E00F41683 /* KarlLayout */ = { 141 | isa = PBXNativeTarget; 142 | buildConfigurationList = E724A5841D64D13E00F41683 /* Build configuration list for PBXNativeTarget "KarlLayout" */; 143 | buildPhases = ( 144 | E724A5691D64D13E00F41683 /* Sources */, 145 | E724A56A1D64D13E00F41683 /* Frameworks */, 146 | E724A56B1D64D13E00F41683 /* Resources */, 147 | ); 148 | buildRules = ( 149 | ); 150 | dependencies = ( 151 | ); 152 | name = KarlLayout; 153 | productName = KarlLayout; 154 | productReference = E724A56D1D64D13E00F41683 /* KarlLayout.app */; 155 | productType = "com.apple.product-type.application"; 156 | }; 157 | /* End PBXNativeTarget section */ 158 | 159 | /* Begin PBXProject section */ 160 | E724A5651D64D13E00F41683 /* Project object */ = { 161 | isa = PBXProject; 162 | attributes = { 163 | LastUpgradeCheck = 0730; 164 | ORGANIZATIONNAME = fx; 165 | TargetAttributes = { 166 | E724A56C1D64D13E00F41683 = { 167 | CreatedOnToolsVersion = 7.3.1; 168 | }; 169 | }; 170 | }; 171 | buildConfigurationList = E724A5681D64D13E00F41683 /* Build configuration list for PBXProject "KarlLayout" */; 172 | compatibilityVersion = "Xcode 3.2"; 173 | developmentRegion = English; 174 | hasScannedForEncodings = 0; 175 | knownRegions = ( 176 | en, 177 | Base, 178 | ); 179 | mainGroup = E724A5641D64D13E00F41683; 180 | productRefGroup = E724A56E1D64D13E00F41683 /* Products */; 181 | projectDirPath = ""; 182 | projectRoot = ""; 183 | targets = ( 184 | E724A56C1D64D13E00F41683 /* KarlLayout */, 185 | ); 186 | }; 187 | /* End PBXProject section */ 188 | 189 | /* Begin PBXResourcesBuildPhase section */ 190 | E724A56B1D64D13E00F41683 /* Resources */ = { 191 | isa = PBXResourcesBuildPhase; 192 | buildActionMask = 2147483647; 193 | files = ( 194 | E724A5911D64D17400F41683 /* Main.storyboard in Resources */, 195 | E724A5801D64D13E00F41683 /* LaunchScreen.storyboard in Resources */, 196 | E724A57D1D64D13E00F41683 /* Assets.xcassets in Resources */, 197 | E724A5AB1D64D65400F41683 /* karl.jpeg in Resources */, 198 | ); 199 | runOnlyForDeploymentPostprocessing = 0; 200 | }; 201 | /* End PBXResourcesBuildPhase section */ 202 | 203 | /* Begin PBXSourcesBuildPhase section */ 204 | E724A5691D64D13E00F41683 /* Sources */ = { 205 | isa = PBXSourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | E724A5C01D64D9BB00F41683 /* KLLayoutElementMaker.m in Sources */, 209 | E724A5BF1D64D9BB00F41683 /* KLLayoutElement.m in Sources */, 210 | E724A5901D64D17400F41683 /* SecondViewController.m in Sources */, 211 | E724A5C31D64D9BB00F41683 /* View+KLLayout.m in Sources */, 212 | E724A5C11D64D9BB00F41683 /* KLLayoutEngine.m in Sources */, 213 | E724A5C21D64D9BB00F41683 /* KLVerticalLayoutCalculator.m in Sources */, 214 | E724A58E1D64D17400F41683 /* AppDelegate.m in Sources */, 215 | E724A5BE1D64D9BB00F41683 /* KLHorizontalLayoutCalculator.m in Sources */, 216 | E724A58F1D64D17400F41683 /* FirstViewController.m in Sources */, 217 | E724A5721D64D13E00F41683 /* main.m in Sources */, 218 | E724A5BD1D64D9BB00F41683 /* KLBaseLayoutCalculator.m in Sources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXSourcesBuildPhase section */ 223 | 224 | /* Begin PBXVariantGroup section */ 225 | E724A57E1D64D13E00F41683 /* LaunchScreen.storyboard */ = { 226 | isa = PBXVariantGroup; 227 | children = ( 228 | E724A57F1D64D13E00F41683 /* Base */, 229 | ); 230 | name = LaunchScreen.storyboard; 231 | sourceTree = ""; 232 | }; 233 | /* End PBXVariantGroup section */ 234 | 235 | /* Begin XCBuildConfiguration section */ 236 | E724A5821D64D13E00F41683 /* Debug */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ALWAYS_SEARCH_USER_PATHS = NO; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 242 | CLANG_CXX_LIBRARY = "libc++"; 243 | CLANG_ENABLE_MODULES = YES; 244 | CLANG_ENABLE_OBJC_ARC = YES; 245 | CLANG_WARN_BOOL_CONVERSION = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 248 | CLANG_WARN_EMPTY_BODY = YES; 249 | CLANG_WARN_ENUM_CONVERSION = YES; 250 | CLANG_WARN_INT_CONVERSION = YES; 251 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 252 | CLANG_WARN_UNREACHABLE_CODE = YES; 253 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 254 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 255 | COPY_PHASE_STRIP = NO; 256 | DEBUG_INFORMATION_FORMAT = dwarf; 257 | ENABLE_STRICT_OBJC_MSGSEND = YES; 258 | ENABLE_TESTABILITY = YES; 259 | GCC_C_LANGUAGE_STANDARD = gnu99; 260 | GCC_DYNAMIC_NO_PIC = NO; 261 | GCC_NO_COMMON_BLOCKS = YES; 262 | GCC_OPTIMIZATION_LEVEL = 0; 263 | GCC_PREPROCESSOR_DEFINITIONS = ( 264 | "DEBUG=1", 265 | "$(inherited)", 266 | ); 267 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 268 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 269 | GCC_WARN_UNDECLARED_SELECTOR = YES; 270 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 271 | GCC_WARN_UNUSED_FUNCTION = YES; 272 | GCC_WARN_UNUSED_VARIABLE = YES; 273 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 274 | MTL_ENABLE_DEBUG_INFO = YES; 275 | ONLY_ACTIVE_ARCH = YES; 276 | SDKROOT = iphoneos; 277 | }; 278 | name = Debug; 279 | }; 280 | E724A5831D64D13E00F41683 /* Release */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | ALWAYS_SEARCH_USER_PATHS = NO; 284 | CLANG_ANALYZER_NONNULL = YES; 285 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 286 | CLANG_CXX_LIBRARY = "libc++"; 287 | CLANG_ENABLE_MODULES = YES; 288 | CLANG_ENABLE_OBJC_ARC = YES; 289 | CLANG_WARN_BOOL_CONVERSION = YES; 290 | CLANG_WARN_CONSTANT_CONVERSION = YES; 291 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 292 | CLANG_WARN_EMPTY_BODY = YES; 293 | CLANG_WARN_ENUM_CONVERSION = YES; 294 | CLANG_WARN_INT_CONVERSION = YES; 295 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 296 | CLANG_WARN_UNREACHABLE_CODE = YES; 297 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 298 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 299 | COPY_PHASE_STRIP = NO; 300 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 301 | ENABLE_NS_ASSERTIONS = NO; 302 | ENABLE_STRICT_OBJC_MSGSEND = YES; 303 | GCC_C_LANGUAGE_STANDARD = gnu99; 304 | GCC_NO_COMMON_BLOCKS = YES; 305 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 306 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 307 | GCC_WARN_UNDECLARED_SELECTOR = YES; 308 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 309 | GCC_WARN_UNUSED_FUNCTION = YES; 310 | GCC_WARN_UNUSED_VARIABLE = YES; 311 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 312 | MTL_ENABLE_DEBUG_INFO = NO; 313 | SDKROOT = iphoneos; 314 | VALIDATE_PRODUCT = YES; 315 | }; 316 | name = Release; 317 | }; 318 | E724A5851D64D13E00F41683 /* Debug */ = { 319 | isa = XCBuildConfiguration; 320 | buildSettings = { 321 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 322 | INFOPLIST_FILE = KarlLayout/Info.plist; 323 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 324 | PRODUCT_BUNDLE_IDENTIFIER = fx.KarlLayout; 325 | PRODUCT_NAME = "$(TARGET_NAME)"; 326 | }; 327 | name = Debug; 328 | }; 329 | E724A5861D64D13E00F41683 /* Release */ = { 330 | isa = XCBuildConfiguration; 331 | buildSettings = { 332 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 333 | INFOPLIST_FILE = KarlLayout/Info.plist; 334 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 335 | PRODUCT_BUNDLE_IDENTIFIER = fx.KarlLayout; 336 | PRODUCT_NAME = "$(TARGET_NAME)"; 337 | }; 338 | name = Release; 339 | }; 340 | /* End XCBuildConfiguration section */ 341 | 342 | /* Begin XCConfigurationList section */ 343 | E724A5681D64D13E00F41683 /* Build configuration list for PBXProject "KarlLayout" */ = { 344 | isa = XCConfigurationList; 345 | buildConfigurations = ( 346 | E724A5821D64D13E00F41683 /* Debug */, 347 | E724A5831D64D13E00F41683 /* Release */, 348 | ); 349 | defaultConfigurationIsVisible = 0; 350 | defaultConfigurationName = Release; 351 | }; 352 | E724A5841D64D13E00F41683 /* Build configuration list for PBXNativeTarget "KarlLayout" */ = { 353 | isa = XCConfigurationList; 354 | buildConfigurations = ( 355 | E724A5851D64D13E00F41683 /* Debug */, 356 | E724A5861D64D13E00F41683 /* Release */, 357 | ); 358 | defaultConfigurationIsVisible = 0; 359 | }; 360 | /* End XCConfigurationList section */ 361 | }; 362 | rootObject = E724A5651D64D13E00F41683 /* Project object */; 363 | } 364 | -------------------------------------------------------------------------------- /KarlLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /KarlLayout/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/4/21. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /KarlLayout/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/4/21. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /KarlLayout/Assets.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" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /KarlLayout/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /KarlLayout/Assets.xcassets/first.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "first.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /KarlLayout/Assets.xcassets/first.imageset/first.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fx91/KarlLayout/2e714abcae81a6ce9201cfbe00dc256800c4b098/KarlLayout/Assets.xcassets/first.imageset/first.pdf -------------------------------------------------------------------------------- /KarlLayout/Assets.xcassets/second.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "second.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /KarlLayout/Assets.xcassets/second.imageset/second.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fx91/KarlLayout/2e714abcae81a6ce9201cfbe00dc256800c4b098/KarlLayout/Assets.xcassets/second.imageset/second.pdf -------------------------------------------------------------------------------- /KarlLayout/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /KarlLayout/FirstViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FirstViewController.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/4/21. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TestCell : UITableViewCell 12 | 13 | @property (nonatomic, strong) UIView *testView; 14 | @property (nonatomic, strong) UILabel *testLabel1; 15 | @property (nonatomic, strong) UILabel *testLabel2; 16 | @property (nonatomic, strong) UIImageView *testImageView; 17 | 18 | @end 19 | 20 | @interface FirstViewController : UIViewController 21 | 22 | 23 | @end 24 | 25 | -------------------------------------------------------------------------------- /KarlLayout/FirstViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FirstViewController.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/4/21. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "FirstViewController.h" 10 | 11 | #import "View+KLLayout.h" 12 | #import "KLLayoutEngine.h" 13 | 14 | @implementation TestCell 15 | 16 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 17 | { 18 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 19 | if (!self) { 20 | return nil; 21 | } 22 | 23 | _testView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 30, 30)]; 24 | _testLabel1 = [[UILabel alloc] initWithFrame:CGRectMake(60, 20, 30, 30)]; 25 | _testLabel2 = [[UILabel alloc] initWithFrame:CGRectMake(100, 20, 30, 30)]; 26 | 27 | [_testLabel1 setText:@"test"]; 28 | 29 | [self addSubview:_testView]; 30 | [self addSubview:_testLabel1]; 31 | [self addSubview:_testLabel2]; 32 | 33 | self.selectionStyle = UITableViewCellSelectionStyleNone; 34 | 35 | [_testView kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 36 | make.width.flexible(YES); 37 | make.top.offset(10); 38 | make.left.offset(10); 39 | make.width.multipliedBy(0.2); 40 | make.height.multipliedBy(0.5).offset(40); 41 | }]; 42 | 43 | [_testLabel1 kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 44 | make.width.flexible(YES); 45 | make.top.offset(10); 46 | make.left.offset(20).multipliedBy(0.2); 47 | make.right.multipliedBy(0.05).offset(10); 48 | make.height.multipliedBy(0.2).offset(20); 49 | }]; 50 | 51 | [_testLabel2 kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 52 | make.width.flexible(YES); 53 | make.top.offset(50); 54 | make.left.offset(20).multipliedBy(0.2); 55 | make.right.multipliedBy(0.05).offset(10); 56 | make.height.multipliedBy(0.4).offset(20); 57 | }]; 58 | 59 | return self; 60 | } 61 | 62 | @end 63 | 64 | @interface FirstViewController () 65 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 66 | 67 | @end 68 | 69 | @implementation FirstViewController 70 | 71 | - (void)viewDidLoad { 72 | [super viewDidLoad]; 73 | 74 | self.tableView.delegate = self; 75 | self.tableView.dataSource = self; 76 | 77 | [self.tableView setTableFooterView:[[UIView alloc] init]]; 78 | 79 | } 80 | 81 | 82 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 83 | { 84 | return 10; 85 | } 86 | 87 | 88 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 89 | { 90 | TestCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Identifier"]; 91 | 92 | if (!cell) { 93 | cell = [[TestCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Identifier"]; 94 | [[KLLayoutEngine sharedEngine] setDebugModeEnable:YES]; 95 | } 96 | 97 | 98 | return cell; 99 | } 100 | 101 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 102 | { 103 | return 120.f; 104 | } 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /KarlLayout/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /KarlLayout/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 60 | 67 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /KarlLayout/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // LongImage 4 | // 5 | // Created by fx on 16/4/21. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SecondViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /KarlLayout/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // LongImage 4 | // 5 | // Created by fx on 16/4/21. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import "SecondViewController.h" 10 | #import "KLLayout.h" 11 | 12 | @interface SecondViewController () 13 | @property (weak, nonatomic) IBOutlet UIView *changeSizeView; 14 | 15 | @property (nonatomic) CGFloat viewHeightScale; 16 | 17 | @property (weak, nonatomic) IBOutlet UIView *testView; 18 | @property (weak, nonatomic) IBOutlet UILabel *testLabel1; 19 | @property (weak, nonatomic) IBOutlet UILabel *testLabel2; 20 | @property (weak, nonatomic) IBOutlet UIImageView *testImageView; 21 | @property (weak, nonatomic) IBOutlet UIButton *testBtn; 22 | 23 | @end 24 | 25 | @implementation SecondViewController 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | self.viewHeightScale = 1.f; 30 | UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchView:)]; 31 | [self.view addGestureRecognizer:pinchGesture]; 32 | 33 | [self testLayoutViews]; 34 | [self.testImageView setImage:[UIImage imageNamed:@"karl.jpeg"]]; 35 | 36 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 37 | [[KLLayoutEngine sharedEngine] setDebugModeEnable:YES]; 38 | }); 39 | } 40 | 41 | - (void)testLayoutViews 42 | { 43 | [self.changeSizeView kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 44 | make.top.multipliedBy(0.0f).offset(70); 45 | make.left.offset(10); 46 | make.height.multipliedBy(self.viewHeightScale * 0.5f).offset(100); 47 | make.width.multipliedBy(self.viewHeightScale * 0.8f).offset(50); 48 | }]; 49 | 50 | [self.testLabel1 kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 51 | make.top.offset(10); 52 | make.left.offset(10); 53 | make.width.multipliedBy(0.6f); 54 | make.height.multipliedBy(0.1f); 55 | }]; 56 | 57 | [self.testLabel2 kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 58 | make.top.offset(60); 59 | make.left.offset(10); 60 | make.width.multipliedBy(0.6f); 61 | make.height.multipliedBy(0.1f); 62 | }]; 63 | 64 | [self.testView kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 65 | make.top.flexible(YES); 66 | make.left.flexible(YES); 67 | make.width.multipliedBy(0.2f); 68 | make.height.multipliedBy(0.2f); 69 | make.bottom.offset(20).flexible(NO); 70 | make.right.offset(20).flexible(NO); 71 | }]; 72 | 73 | [self.testBtn kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 74 | make.width.multipliedBy(0.4f); 75 | make.top.offset(120); 76 | make.right.offset(10); 77 | }]; 78 | 79 | [self.testImageView kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 80 | make.width.flexible(YES); 81 | make.height.flexible(YES); 82 | make.top.offset(200).flexible(NO); 83 | make.bottom.offset(10).flexible(NO); 84 | make.left.offset(10).flexible(NO); 85 | make.right.offset(100).flexible(NO); 86 | 87 | }]; 88 | } 89 | 90 | - (void) pinchView:(UIPinchGestureRecognizer *)pinchGestureRecognizer 91 | { 92 | if (pinchGestureRecognizer.state == UIGestureRecognizerStateBegan || pinchGestureRecognizer.state == UIGestureRecognizerStateChanged) { 93 | if (pinchGestureRecognizer.scale > 0.3f) { 94 | self.viewHeightScale = pinchGestureRecognizer.scale; 95 | } 96 | 97 | 98 | [self testLayoutViews]; 99 | 100 | // [self.changeSizeView kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 101 | // make.top.offset(70); 102 | // make.left.offset(10); 103 | // make.height.multipliedBy(self.viewHeightScale * 0.5f); 104 | // make.width.multipliedBy(self.viewHeightScale * 0.8f); 105 | // }]; 106 | } 107 | } 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /KarlLayout/karl.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fx91/KarlLayout/2e714abcae81a6ce9201cfbe00dc256800c4b098/KarlLayout/karl.jpeg -------------------------------------------------------------------------------- /KarlLayout/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // KarlLayout 4 | // 5 | // Created by fx on 16/8/18. 6 | // Copyright © 2016年 fx. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KarlLayout 2 | 3 | 用于处理基于父视图的排版 4 | 5 | 参考Masonry的语法 6 | 7 | 可以通过指定上下,左右,长宽的基于父视图的比例和偏移确定自己的大小和位置。同时支持AutoResizeMask的简单添加。 8 | 9 | ##example 10 | 11 | 12 | [_testView kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 13 | make.width.flexible(YES); 14 | make.top.offset(10); 15 | make.left.offset(10); 16 | make.width.multipliedBy(0.2); 17 | make.height.multipliedBy(0.5).offset(40); 18 | }]; 19 | 20 | [_testLabel1 kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 21 | make.width.flexible(YES); 22 | make.top.offset(10); 23 | make.left.offset(20).multipliedBy(0.2); 24 | make.right.multipliedBy(0.05).offset(10); 25 | make.height.multipliedBy(0.2).offset(20); 26 | }]; 27 | 28 | [_testLabel2 kl_makeLayoutElement:^(KLLayoutElementMaker *make) { 29 | make.width.flexible(YES); 30 | make.top.offset(50); 31 | make.left.offset(20).multipliedBy(0.2); 32 | make.right.multipliedBy(0.05).offset(10); 33 | make.height.multipliedBy(0.4).offset(20); 34 | }]; 35 | 36 | 可以简单适配各个屏幕的cell样式 37 | 38 | ####iphone5 39 | ![](5.png) 40 | 41 | 42 | ####iphone6 43 | ![](6.png) 44 | 45 | 46 | ####iphone6 plus 47 | ![](6p.png) 48 | 49 | --------------------------------------------------------------------------------