Files
featherVoice/TUIKit/TUICore/UIView+TUILayout.m
2025-08-08 10:49:36 +08:00

358 lines
8.8 KiB
Objective-C

// 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