├── README.md ├── UIView+Utils.h ├── UIView+Utils.m └── UIViewUtils.podspec /README.md: -------------------------------------------------------------------------------- 1 | UIView-Utils 2 | ============ 3 | 4 | It's a category to make you layout views more easily. Borrowed from Three20 / DTFoundation, inspired By [Limboy](http://blog.leezhong.com) 5 | 6 | ------- 7 | ## Other similar sources: 8 | [FrameAccessor](https://github.com/AlexDenisov/FrameAccessor) 9 | 10 | [UIView+frameAdjust](https://gist.github.com/tangqiaoboy/8131327) 11 | 12 | -------------------------------------------------------------------------------- /UIView+Utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Utils.h 3 | // Borrowed from Three20 / DTFoundation 4 | // 5 | // Copyright (c) 2013 iOS. No rights reserved. 6 | // 7 | 8 | #import 9 | 10 | 11 | @interface UIView (Utils) 12 | 13 | /** 14 | * Shortcut for frame.origin.x. 15 | * 16 | * Sets frame.origin.x = left 17 | */ 18 | @property (nonatomic) CGFloat left; 19 | 20 | /** 21 | * Shortcut for frame.origin.y 22 | * 23 | * Sets frame.origin.y = top 24 | */ 25 | @property (nonatomic) CGFloat top; 26 | 27 | /** 28 | * Shortcut for frame.origin.x + frame.size.width 29 | * 30 | * Sets frame.origin.x = right - frame.size.width 31 | */ 32 | @property (nonatomic) CGFloat right; 33 | 34 | /** 35 | * Shortcut for frame.origin.y + frame.size.height 36 | * 37 | * Sets frame.origin.y = bottom - frame.size.height 38 | */ 39 | @property (nonatomic) CGFloat bottom; 40 | 41 | /** 42 | * Shortcut for frame.size.width 43 | * 44 | * Sets frame.size.width = width 45 | */ 46 | @property (nonatomic) CGFloat width; 47 | 48 | /** 49 | * Shortcut for frame.size.height 50 | * 51 | * Sets frame.size.height = height 52 | */ 53 | @property (nonatomic) CGFloat height; 54 | 55 | /** 56 | * Shortcut for center.x 57 | * 58 | * Sets center.x = centerX 59 | */ 60 | @property (nonatomic) CGFloat centerX; 61 | 62 | /** 63 | * Shortcut for center.y 64 | * 65 | * Sets center.y = centerY 66 | */ 67 | @property (nonatomic) CGFloat centerY; 68 | 69 | /** 70 | * Return the x coordinate on the screen. 71 | */ 72 | @property (nonatomic, readonly) CGFloat screenX; 73 | 74 | /** 75 | * Return the y coordinate on the screen. 76 | */ 77 | @property (nonatomic, readonly) CGFloat screenY; 78 | 79 | /** 80 | * Return the x coordinate on the screen, taking into account scroll views. 81 | */ 82 | @property (nonatomic, readonly) CGFloat screenViewX; 83 | 84 | /** 85 | * Return the y coordinate on the screen, taking into account scroll views. 86 | */ 87 | @property (nonatomic, readonly) CGFloat screenViewY; 88 | 89 | /** 90 | * Return the view frame on the screen, taking into account scroll views. 91 | */ 92 | @property (nonatomic, readonly) CGRect screenFrame; 93 | 94 | /** 95 | * Shortcut for frame.origin 96 | */ 97 | @property (nonatomic) CGPoint origin; 98 | 99 | /** 100 | * Shortcut for frame.size 101 | */ 102 | @property (nonatomic) CGSize size; 103 | 104 | /** 105 | * Return the width in portrait or the height in landscape. 106 | */ 107 | @property (nonatomic, readonly) CGFloat orientationWidth; 108 | 109 | /** 110 | * Return the height in portrait or the width in landscape. 111 | */ 112 | @property (nonatomic, readonly) CGFloat orientationHeight; 113 | 114 | /** 115 | * Finds the first descendant view (including this view) that is a member of a particular class. 116 | */ 117 | - (UIView*)descendantOrSelfWithClass:(Class)cls; 118 | 119 | /** 120 | * Finds the first ancestor view (including this view) that is a member of a particular class. 121 | */ 122 | - (UIView*)ancestorOrSelfWithClass:(Class)cls; 123 | 124 | /** 125 | * Removes all subviews. 126 | */ 127 | - (void)removeAllSubviews; 128 | 129 | /** 130 | Attaches the given block for a single tap action to the receiver. 131 | @param block The block to execute. 132 | */ 133 | - (void)setTapActionWithBlock:(void (^)(void))block; 134 | 135 | /** 136 | Attaches the given block for a long press action to the receiver. 137 | @param block The block to execute. 138 | */ 139 | - (void)setLongPressActionWithBlock:(void (^)(void))block; 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /UIView+Utils.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Utils.m 3 | // Borrowed from Three20 4 | // 5 | // Copyright (c) 2013 iOS. No rights reserved. 6 | // 7 | 8 | #import "UIView+Utils.h" 9 | 10 | #import 11 | 12 | static char kDTActionHandlerTapBlockKey; 13 | static char kDTActionHandlerTapGestureKey; 14 | static char kDTActionHandlerLongPressBlockKey; 15 | static char kDTActionHandlerLongPressGestureKey; 16 | 17 | @implementation UIView (Utils) 18 | 19 | 20 | - (CGFloat)left { 21 | return self.frame.origin.x; 22 | } 23 | 24 | 25 | 26 | - (void)setLeft:(CGFloat)x { 27 | CGRect frame = self.frame; 28 | frame.origin.x = x; 29 | self.frame = frame; 30 | } 31 | 32 | 33 | 34 | - (CGFloat)top { 35 | return self.frame.origin.y; 36 | } 37 | 38 | 39 | 40 | - (void)setTop:(CGFloat)y { 41 | CGRect frame = self.frame; 42 | frame.origin.y = y; 43 | self.frame = frame; 44 | } 45 | 46 | 47 | 48 | - (CGFloat)right { 49 | return self.frame.origin.x + self.frame.size.width; 50 | } 51 | 52 | 53 | 54 | - (void)setRight:(CGFloat)right { 55 | CGRect frame = self.frame; 56 | frame.origin.x = right - frame.size.width; 57 | self.frame = frame; 58 | } 59 | 60 | 61 | 62 | - (CGFloat)bottom { 63 | return self.frame.origin.y + self.frame.size.height; 64 | } 65 | 66 | 67 | 68 | - (void)setBottom:(CGFloat)bottom { 69 | CGRect frame = self.frame; 70 | frame.origin.y = bottom - frame.size.height; 71 | self.frame = frame; 72 | } 73 | 74 | 75 | 76 | - (CGFloat)centerX { 77 | return self.center.x; 78 | } 79 | 80 | 81 | 82 | - (void)setCenterX:(CGFloat)centerX { 83 | self.center = CGPointMake(centerX, self.center.y); 84 | } 85 | 86 | 87 | 88 | - (CGFloat)centerY { 89 | return self.center.y; 90 | } 91 | 92 | 93 | 94 | - (void)setCenterY:(CGFloat)centerY { 95 | self.center = CGPointMake(self.center.x, centerY); 96 | } 97 | 98 | 99 | 100 | - (CGFloat)width { 101 | return self.frame.size.width; 102 | } 103 | 104 | 105 | 106 | - (void)setWidth:(CGFloat)width { 107 | CGRect frame = self.frame; 108 | frame.size.width = width; 109 | self.frame = frame; 110 | } 111 | 112 | 113 | 114 | - (CGFloat)height { 115 | return self.frame.size.height; 116 | } 117 | 118 | 119 | 120 | - (void)setHeight:(CGFloat)height { 121 | CGRect frame = self.frame; 122 | frame.size.height = height; 123 | self.frame = frame; 124 | } 125 | 126 | 127 | 128 | - (CGFloat)screenX { 129 | CGFloat x = 0.0f; 130 | for (UIView* view = self; view; view = view.superview) { 131 | x += view.left; 132 | } 133 | return x; 134 | } 135 | 136 | 137 | 138 | - (CGFloat)screenY { 139 | CGFloat y = 0.0f; 140 | for (UIView* view = self; view; view = view.superview) { 141 | y += view.top; 142 | } 143 | return y; 144 | } 145 | 146 | 147 | 148 | - (CGFloat)screenViewX { 149 | CGFloat x = 0.0f; 150 | for (UIView* view = self; view; view = view.superview) { 151 | x += view.left; 152 | 153 | if ([view isKindOfClass:[UIScrollView class]]) { 154 | UIScrollView* scrollView = (UIScrollView*)view; 155 | x -= scrollView.contentOffset.x; 156 | } 157 | } 158 | 159 | return x; 160 | } 161 | 162 | 163 | 164 | - (CGFloat)screenViewY { 165 | CGFloat y = 0; 166 | for (UIView* view = self; view; view = view.superview) { 167 | y += view.top; 168 | 169 | if ([view isKindOfClass:[UIScrollView class]]) { 170 | UIScrollView* scrollView = (UIScrollView*)view; 171 | y -= scrollView.contentOffset.y; 172 | } 173 | } 174 | return y; 175 | } 176 | 177 | 178 | 179 | - (CGRect)screenFrame { 180 | return CGRectMake(self.screenViewX, self.screenViewY, self.width, self.height); 181 | } 182 | 183 | 184 | 185 | - (CGPoint)origin { 186 | return self.frame.origin; 187 | } 188 | 189 | 190 | 191 | - (void)setOrigin:(CGPoint)origin { 192 | CGRect frame = self.frame; 193 | frame.origin = origin; 194 | self.frame = frame; 195 | } 196 | 197 | 198 | 199 | - (CGSize)size { 200 | return self.frame.size; 201 | } 202 | 203 | 204 | 205 | - (void)setSize:(CGSize)size { 206 | CGRect frame = self.frame; 207 | frame.size = size; 208 | self.frame = frame; 209 | } 210 | 211 | 212 | 213 | - (CGFloat)orientationWidth { 214 | return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) 215 | ? self.height : self.width; 216 | } 217 | 218 | 219 | 220 | - (CGFloat)orientationHeight { 221 | return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) 222 | ? self.width : self.height; 223 | } 224 | 225 | 226 | 227 | - (UIView*)descendantOrSelfWithClass:(Class)cls { 228 | if ([self isKindOfClass:cls]) 229 | return self; 230 | 231 | for (UIView* child in self.subviews) { 232 | UIView* it = [child descendantOrSelfWithClass:cls]; 233 | if (it) 234 | return it; 235 | } 236 | 237 | return nil; 238 | } 239 | 240 | 241 | 242 | - (UIView*)ancestorOrSelfWithClass:(Class)cls { 243 | if ([self isKindOfClass:cls]) { 244 | return self; 245 | 246 | } else if (self.superview) { 247 | return [self.superview ancestorOrSelfWithClass:cls]; 248 | 249 | } else { 250 | return nil; 251 | } 252 | } 253 | 254 | 255 | 256 | - (void)removeAllSubviews { 257 | while (self.subviews.count) { 258 | UIView* child = self.subviews.lastObject; 259 | [child removeFromSuperview]; 260 | } 261 | } 262 | 263 | 264 | 265 | - (CGPoint)offsetFromView:(UIView*)otherView { 266 | CGFloat x = 0.0f, y = 0.0f; 267 | for (UIView* view = self; view && view != otherView; view = view.superview) { 268 | x += view.left; 269 | y += view.top; 270 | } 271 | return CGPointMake(x, y); 272 | } 273 | 274 | 275 | - (void)setTapActionWithBlock:(void (^)(void))block 276 | { 277 | UITapGestureRecognizer *gesture = objc_getAssociatedObject(self, &kDTActionHandlerTapGestureKey); 278 | 279 | if (!gesture) 280 | { 281 | gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(__handleActionForTapGesture:)]; 282 | [self addGestureRecognizer:gesture]; 283 | objc_setAssociatedObject(self, &kDTActionHandlerTapGestureKey, gesture, OBJC_ASSOCIATION_RETAIN); 284 | } 285 | 286 | objc_setAssociatedObject(self, &kDTActionHandlerTapBlockKey, block, OBJC_ASSOCIATION_COPY); 287 | } 288 | 289 | - (void)__handleActionForTapGesture:(UITapGestureRecognizer *)gesture 290 | { 291 | if (gesture.state == UIGestureRecognizerStateRecognized) 292 | { 293 | void(^action)(void) = objc_getAssociatedObject(self, &kDTActionHandlerTapBlockKey); 294 | 295 | if (action) 296 | { 297 | action(); 298 | } 299 | } 300 | } 301 | 302 | - (void)setLongPressActionWithBlock:(void (^)(void))block 303 | { 304 | UILongPressGestureRecognizer *gesture = objc_getAssociatedObject(self, &kDTActionHandlerLongPressGestureKey); 305 | 306 | if (!gesture) 307 | { 308 | gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(__handleActionForLongPressGesture:)]; 309 | [self addGestureRecognizer:gesture]; 310 | objc_setAssociatedObject(self, &kDTActionHandlerLongPressGestureKey, gesture, OBJC_ASSOCIATION_RETAIN); 311 | } 312 | 313 | objc_setAssociatedObject(self, &kDTActionHandlerLongPressBlockKey, block, OBJC_ASSOCIATION_COPY); 314 | } 315 | 316 | - (void)__handleActionForLongPressGesture:(UITapGestureRecognizer *)gesture 317 | { 318 | if (gesture.state == UIGestureRecognizerStateBegan) 319 | { 320 | void(^action)(void) = objc_getAssociatedObject(self, &kDTActionHandlerLongPressBlockKey); 321 | 322 | if (action) 323 | { 324 | action(); 325 | } 326 | } 327 | } 328 | 329 | @end 330 | -------------------------------------------------------------------------------- /UIViewUtils.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'UIViewUtils' 3 | spec.version = '0.0.1' 4 | spec.summary = 'UIViewUtils' 5 | spec.source_files = '*.{h,m}' 6 | spec.requires_arc = true 7 | spec.ios.deployment_target = '5.0' 8 | end 9 | 10 | --------------------------------------------------------------------------------