358 lines
8.8 KiB
Mathematica
358 lines
8.8 KiB
Mathematica
|
|
|
||
|
|
// Created by Tencent on 2023/06/09.
|
||
|
|
// Copyright © 2023 Tencent. All rights reserved.
|
||
|
|
#import <objc/runtime.h>
|
||
|
|
#import "UIView+TUILayout.h"
|
||
|
|
|
||
|
|
@implementation UIView (TUILayout)
|
||
|
|
|
||
|
|
#pragma mark - frame
|
||
|
|
- (void)setMm_x:(CGFloat)mm_x {
|
||
|
|
CGRect frame = self.frame;
|
||
|
|
frame.origin.x = mm_x;
|
||
|
|
self.frame = frame;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_x {
|
||
|
|
return self.frame.origin.x;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)setMm_y:(CGFloat)mm_y {
|
||
|
|
CGRect frame = self.frame;
|
||
|
|
frame.origin.y = mm_y;
|
||
|
|
self.frame = frame;
|
||
|
|
}
|
||
|
|
- (CGFloat)mm_y {
|
||
|
|
return self.frame.origin.y;
|
||
|
|
}
|
||
|
|
- (void)setMm_w:(CGFloat)mm_w {
|
||
|
|
CGRect frame = self.frame;
|
||
|
|
frame.size.width = mm_w;
|
||
|
|
self.frame = frame;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_w {
|
||
|
|
return self.frame.size.width;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)setMm_h:(CGFloat)mm_h {
|
||
|
|
CGRect frame = self.frame;
|
||
|
|
frame.size.height = mm_h;
|
||
|
|
self.frame = frame;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_h {
|
||
|
|
return self.frame.size.height;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGPoint)mm_origin {
|
||
|
|
return self.frame.origin;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)setMm_origin:(CGPoint)mm_origin {
|
||
|
|
CGRect frame = self.frame;
|
||
|
|
frame.origin = mm_origin;
|
||
|
|
self.frame = frame;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGSize)mm_size {
|
||
|
|
return self.frame.size;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)setMm_size:(CGSize)size {
|
||
|
|
CGRect frame = self.frame;
|
||
|
|
frame.size = size;
|
||
|
|
self.frame = frame;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_centerX {
|
||
|
|
return self.center.x;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_centerY {
|
||
|
|
return self.center.y;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)setMm_centerX:(CGFloat)mm_centerX {
|
||
|
|
CGPoint center = self.center;
|
||
|
|
center.x = mm_centerX;
|
||
|
|
self.center = center;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)setMm_centerY:(CGFloat)mm_centerY {
|
||
|
|
CGPoint center = self.center;
|
||
|
|
center.y = mm_centerY;
|
||
|
|
self.center = center;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_r {
|
||
|
|
NSCAssert(self.superview, @"must add subview first");
|
||
|
|
return self.superview.mm_w - self.mm_maxX;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)setMm_r:(CGFloat)mm_r {
|
||
|
|
self.mm_x += self.mm_r - mm_r;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_b {
|
||
|
|
NSCAssert(self.superview, @"must add subview first");
|
||
|
|
return self.superview.mm_h - self.mm_maxY;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)setMm_b:(CGFloat)mm_b {
|
||
|
|
self.mm_y += self.mm_b - mm_b;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_maxY {
|
||
|
|
return CGRectGetMaxY(self.frame);
|
||
|
|
}
|
||
|
|
- (CGFloat)mm_minY {
|
||
|
|
return CGRectGetMinY(self.frame);
|
||
|
|
}
|
||
|
|
- (CGFloat)mm_maxX {
|
||
|
|
return CGRectGetMaxX(self.frame);
|
||
|
|
}
|
||
|
|
- (CGFloat)mm_minX {
|
||
|
|
return CGRectGetMinX(self.frame);
|
||
|
|
}
|
||
|
|
|
||
|
|
#pragma mark - chain call
|
||
|
|
|
||
|
|
- (UIView * (^)(CGFloat))mm_top {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat m_top) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
self.mm_y = m_top;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(CGFloat))mm_bottom {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat m_bottom) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
self.mm_b = m_bottom;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
- (UIView * (^)(CGFloat))mm_flexToBottom {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat m_flexToBottom) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
self.mm_h += self.mm_b - m_flexToBottom;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
- (UIView * (^)(CGFloat))mm_left {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat m_left) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
self.mm_x = m_left;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(CGFloat))mm_right {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat m_right) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
self.mm_r = m_right;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
- (UIView * (^)(CGFloat))mm_flexToRight {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat m_flexToRight) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
self.mm_w += self.mm_r - m_flexToRight;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(CGFloat))mm_width {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat m_width) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
self.mm_w = m_width;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(CGFloat))mm_height {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat m_height) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
self.mm_h = m_height;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(CGFloat))mm__centerX {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat x) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
NSAssert(self.mm_w, @"must set width first");
|
||
|
|
self.mm_centerX = x;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(CGFloat))mm__centerY {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat y) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
NSAssert(self.mm_h, @"must set height first");
|
||
|
|
self.mm_centerY = y;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(void))tui_mm_center {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^{
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
if (self.superview) {
|
||
|
|
self.mm_centerX = self.superview.mm_w / 2;
|
||
|
|
self.mm_centerY = self.superview.mm_h / 2;
|
||
|
|
}
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(void))mm_fill {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^{
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
if (self.superview) {
|
||
|
|
self.mm_x = self.mm_y = 0;
|
||
|
|
self.mm_w = self.superview.mm_w;
|
||
|
|
self.mm_h = self.superview.mm_h;
|
||
|
|
}
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(void))mm_sizeToFit {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^{
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
[self sizeToFit];
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
- (UIView * (^)(CGFloat w, CGFloat h))mm_sizeToFitThan {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat w, CGFloat h) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
[self sizeToFit];
|
||
|
|
if (self.mm_w < w) self.mm_w = w;
|
||
|
|
if (self.mm_h < h) self.mm_h = h;
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(CGFloat space))mm_hstack {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat space) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
if (self.mm_sibling) {
|
||
|
|
self.mm__centerY(self.mm_sibling.mm_centerY).mm_left(self.mm_sibling.mm_maxX + space);
|
||
|
|
}
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView * (^)(CGFloat space))mm_vstack {
|
||
|
|
@tui_mm_weakify(self);
|
||
|
|
return ^(CGFloat space) {
|
||
|
|
@tui_mm_strongify(self);
|
||
|
|
if (self.mm_sibling) {
|
||
|
|
self.mm__centerX(self.mm_sibling.mm_centerX).mm_top(self.mm_sibling.mm_maxY + space);
|
||
|
|
}
|
||
|
|
return self;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIView *)mm_sibling {
|
||
|
|
NSUInteger idx = [self.superview.subviews indexOfObject:self];
|
||
|
|
if (idx == 0 || idx == NSNotFound) return nil;
|
||
|
|
return self.superview.subviews[idx - 1];
|
||
|
|
}
|
||
|
|
|
||
|
|
- (UIViewController *)mm_viewController {
|
||
|
|
UIView *view = self;
|
||
|
|
while (view) {
|
||
|
|
UIResponder *nextResponder = [view nextResponder];
|
||
|
|
if ([nextResponder isKindOfClass:[UIViewController class]]) {
|
||
|
|
return (UIViewController *)nextResponder;
|
||
|
|
}
|
||
|
|
view = view.superview;
|
||
|
|
}
|
||
|
|
return nil;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void *gTUIViewLayoutMethodPropertyBottomGap = &gTUIViewLayoutMethodPropertyBottomGap;
|
||
|
|
static void *gTUIViewLayoutMethodPropertyTopGap = &gTUIViewLayoutMethodPropertyTopGap;
|
||
|
|
static void *gTUIViewLayoutMethodPropertyLeftGap = &gTUIViewLayoutMethodPropertyLeftGap;
|
||
|
|
static void *gTUIViewLayoutMethodPropertyRightGap = &gTUIViewLayoutMethodPropertyRightGap;
|
||
|
|
|
||
|
|
- (CGFloat)mm_safeAreaBottomGap {
|
||
|
|
NSNumber *gap = objc_getAssociatedObject(self, gTUIViewLayoutMethodPropertyBottomGap);
|
||
|
|
if (gap == nil) {
|
||
|
|
if (@available(iOS 11, *)) {
|
||
|
|
if (self.superview.safeAreaLayoutGuide.layoutFrame.size.height > 0) {
|
||
|
|
gap = @((self.superview.mm_h - self.superview.safeAreaLayoutGuide.layoutFrame.origin.y -
|
||
|
|
self.superview.safeAreaLayoutGuide.layoutFrame.size.height));
|
||
|
|
} else {
|
||
|
|
gap = nil;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
gap = @(0);
|
||
|
|
}
|
||
|
|
objc_setAssociatedObject(self, gTUIViewLayoutMethodPropertyBottomGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||
|
|
}
|
||
|
|
return gap.floatValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_safeAreaTopGap {
|
||
|
|
NSNumber *gap = objc_getAssociatedObject(self, gTUIViewLayoutMethodPropertyTopGap);
|
||
|
|
if (gap == nil) {
|
||
|
|
if (@available(iOS 11, *)) {
|
||
|
|
gap = @(self.superview.safeAreaLayoutGuide.layoutFrame.origin.y);
|
||
|
|
} else {
|
||
|
|
gap = @(0);
|
||
|
|
}
|
||
|
|
objc_setAssociatedObject(self, gTUIViewLayoutMethodPropertyTopGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||
|
|
}
|
||
|
|
return gap.floatValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_safeAreaLeftGap {
|
||
|
|
NSNumber *gap = objc_getAssociatedObject(self, gTUIViewLayoutMethodPropertyLeftGap);
|
||
|
|
if (gap == nil) {
|
||
|
|
if (@available(iOS 11, *)) {
|
||
|
|
gap = @(self.superview.safeAreaLayoutGuide.layoutFrame.origin.x);
|
||
|
|
} else {
|
||
|
|
gap = @(0);
|
||
|
|
}
|
||
|
|
objc_setAssociatedObject(self, gTUIViewLayoutMethodPropertyLeftGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||
|
|
}
|
||
|
|
return gap.floatValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CGFloat)mm_safeAreaRightGap {
|
||
|
|
NSNumber *gap = objc_getAssociatedObject(self, gTUIViewLayoutMethodPropertyRightGap);
|
||
|
|
if (gap == nil) {
|
||
|
|
if (@available(iOS 11, *)) {
|
||
|
|
gap =
|
||
|
|
@((self.superview.mm_w - self.superview.safeAreaLayoutGuide.layoutFrame.origin.x - self.superview.safeAreaLayoutGuide.layoutFrame.size.width));
|
||
|
|
} else {
|
||
|
|
gap = @(0);
|
||
|
|
}
|
||
|
|
objc_setAssociatedObject(self, gTUIViewLayoutMethodPropertyRightGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||
|
|
}
|
||
|
|
return gap.floatValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
@end
|