// // UIView+SDAutoLayout.m // // Created by gsd on 15/10/6. // Copyright (c) 2015年 gsd. All rights reserved. // /* ********************************************************************************* * * * 在您使用此自动布局库的过程中如果出现bug请及时以以下任意一种方式联系我们,我们会及时修复bug并 * * 帮您解决问题。 * * QQ : 2689718696(gsdios) * * Email : gsdios@126.com * * GitHub: https://github.com/gsdios * * 新浪微博:GSD_iOS * * * ********************************************************************************* */ #import "UIView+SDAutoLayout.h" #import "UITableView+SDAutoTableViewCellHeight.h" #import Class cellContVClass() { // 为了应付SB审核的SB条款 The use of non-public APIs is not permitted on the App Store because it can lead to a poor user experience should these APIs change. static UITableViewCell *tempCell; if (!tempCell) { tempCell = [UITableViewCell new]; } return [tempCell.contentView class]; } @interface SDAutoLayoutModel () @property (nonatomic, strong) SDAutoLayoutModelItem *width; @property (nonatomic, strong) SDAutoLayoutModelItem *height; @property (nonatomic, strong) SDAutoLayoutModelItem *left; @property (nonatomic, strong) SDAutoLayoutModelItem *top; @property (nonatomic, strong) SDAutoLayoutModelItem *right; @property (nonatomic, strong) SDAutoLayoutModelItem *bottom; @property (nonatomic, strong) NSNumber *centerX; @property (nonatomic, strong) NSNumber *centerY; @property (nonatomic, strong) NSNumber *maxWidth; @property (nonatomic, strong) NSNumber *maxHeight; @property (nonatomic, strong) NSNumber *minWidth; @property (nonatomic, strong) NSNumber *minHeight; @property (nonatomic, strong) SDAutoLayoutModelItem *ratio_width; @property (nonatomic, strong) SDAutoLayoutModelItem *ratio_height; @property (nonatomic, strong) SDAutoLayoutModelItem *ratio_left; @property (nonatomic, strong) SDAutoLayoutModelItem *ratio_top; @property (nonatomic, strong) SDAutoLayoutModelItem *ratio_right; @property (nonatomic, strong) SDAutoLayoutModelItem *ratio_bottom; @property (nonatomic, strong) SDAutoLayoutModelItem *equalLeft; @property (nonatomic, strong) SDAutoLayoutModelItem *equalRight; @property (nonatomic, strong) SDAutoLayoutModelItem *equalTop; @property (nonatomic, strong) SDAutoLayoutModelItem *equalBottom; @property (nonatomic, strong) SDAutoLayoutModelItem *equalCenterX; @property (nonatomic, strong) SDAutoLayoutModelItem *equalCenterY; @property (nonatomic, strong) SDAutoLayoutModelItem *widthEqualHeight; @property (nonatomic, strong) SDAutoLayoutModelItem *heightEqualWidth; @property (nonatomic, strong) SDAutoLayoutModelItem *lastModelItem; @end @implementation SDAutoLayoutModel @synthesize leftSpaceToView = _leftSpaceToView; @synthesize rightSpaceToView = _rightSpaceToView; @synthesize topSpaceToView = _topSpaceToView; @synthesize bottomSpaceToView = _bottomSpaceToView; @synthesize widthIs = _widthIs; @synthesize heightIs = _heightIs; @synthesize widthRatioToView = _widthRatioToView; @synthesize heightRatioToView = _heightRatioToView; @synthesize leftEqualToView = _leftEqualToView; @synthesize rightEqualToView = _rightEqualToView; @synthesize topEqualToView = _topEqualToView; @synthesize bottomEqualToView = _bottomEqualToView; @synthesize centerXEqualToView = _centerXEqualToView; @synthesize centerYEqualToView = _centerYEqualToView; @synthesize xIs = _xIs; @synthesize yIs = _yIs; @synthesize centerXIs = _centerXIs; @synthesize centerYIs = _centerYIs; @synthesize autoHeightRatio = _autoHeightRatio; @synthesize autoWidthRatio = _autoWidthRatio; @synthesize spaceToSuperView = _spaceToSuperView; @synthesize maxWidthIs = _maxWidthIs; @synthesize maxHeightIs = _maxHeightIs; @synthesize minWidthIs = _minWidthIs; @synthesize minHeightIs = _minHeightIs; @synthesize widthEqualToHeight = _widthEqualToHeight; @synthesize heightEqualToWidth = _heightEqualToWidth; @synthesize offset = _offset; - (MarginToView)leftSpaceToView { if (!_leftSpaceToView) { _leftSpaceToView = [self marginToViewblockWithKey:@"left"]; } return _leftSpaceToView; } - (MarginToView)rightSpaceToView { if (!_rightSpaceToView) { _rightSpaceToView = [self marginToViewblockWithKey:@"right"]; } return _rightSpaceToView; } - (MarginToView)topSpaceToView { if (!_topSpaceToView) { _topSpaceToView = [self marginToViewblockWithKey:@"top"]; } return _topSpaceToView; } - (MarginToView)bottomSpaceToView { if (!_bottomSpaceToView) { _bottomSpaceToView = [self marginToViewblockWithKey:@"bottom"]; } return _bottomSpaceToView; } - (MarginToView)marginToViewblockWithKey:(NSString *)key { __weak typeof(self) weakSelf = self; return ^(id viewOrViewsArray, CGFloat value) { SDAutoLayoutModelItem *item = [SDAutoLayoutModelItem new]; item.value = @(value); if ([viewOrViewsArray isKindOfClass:[UIView class]]) { item.refView = viewOrViewsArray; } else if ([viewOrViewsArray isKindOfClass:[NSArray class]]) { item.refViewsArray = [viewOrViewsArray copy]; } [weakSelf setValue:item forKey:key]; return weakSelf; }; } - (WidthHeight)widthIs { if (!_widthIs) { __weak typeof(self) weakSelf = self; _widthIs = ^(CGFloat value) { weakSelf.needsAutoResizeView.fixedWidth = @(value); SDAutoLayoutModelItem *widthItem = [SDAutoLayoutModelItem new]; widthItem.value = @(value); weakSelf.width = widthItem; return weakSelf; }; } return _widthIs; } - (WidthHeight)heightIs { if (!_heightIs) { __weak typeof(self) weakSelf = self; _heightIs = ^(CGFloat value) { weakSelf.needsAutoResizeView.fixedHeight = @(value); SDAutoLayoutModelItem *heightItem = [SDAutoLayoutModelItem new]; heightItem.value = @(value); weakSelf.height = heightItem; return weakSelf; }; } return _heightIs; } - (WidthHeightEqualToView)widthRatioToView { if (!_widthRatioToView) { __weak typeof(self) weakSelf = self; _widthRatioToView = ^(UIView *view, CGFloat value) { weakSelf.ratio_width = [SDAutoLayoutModelItem new]; weakSelf.ratio_width.value = @(value); weakSelf.ratio_width.refView = view; return weakSelf; }; } return _widthRatioToView; } - (WidthHeightEqualToView)heightRatioToView { if (!_heightRatioToView) { __weak typeof(self) weakSelf = self; _heightRatioToView = ^(UIView *view, CGFloat value) { weakSelf.ratio_height = [SDAutoLayoutModelItem new]; weakSelf.ratio_height.refView = view; weakSelf.ratio_height.value = @(value); return weakSelf; }; } return _heightRatioToView; } - (WidthHeight)maxWidthIs { if (!_maxWidthIs) { _maxWidthIs = [self limitingWidthHeightWithKey:@"maxWidth"]; } return _maxWidthIs; } - (WidthHeight)maxHeightIs { if (!_maxHeightIs) { _maxHeightIs = [self limitingWidthHeightWithKey:@"maxHeight"]; } return _maxHeightIs; } - (WidthHeight)minWidthIs { if (!_minWidthIs) { _minWidthIs = [self limitingWidthHeightWithKey:@"minWidth"]; } return _minWidthIs; } - (WidthHeight)minHeightIs { if (!_minHeightIs) { _minHeightIs = [self limitingWidthHeightWithKey:@"minHeight"]; } return _minHeightIs; } - (WidthHeight)limitingWidthHeightWithKey:(NSString *)key { __weak typeof(self) weakSelf = self; return ^(CGFloat value) { [weakSelf setValue:@(value) forKey:key]; return weakSelf; }; } - (MarginEqualToView)marginEqualToViewBlockWithKey:(NSString *)key { __weak typeof(self) weakSelf = self; return ^(UIView *view) { SDAutoLayoutModelItem *item = [SDAutoLayoutModelItem new]; item.refView = view; [weakSelf setValue:item forKey:key]; weakSelf.lastModelItem = item; if ([view isKindOfClass:cellContVClass()] && ([key isEqualToString:@"equalCenterY"] || [key isEqualToString:@"equalBottom"])) { view.shouldReadjustFrameBeforeStoreCache = YES; } return weakSelf; }; } - (MarginEqualToView)leftEqualToView { if (!_leftEqualToView) { _leftEqualToView = [self marginEqualToViewBlockWithKey:@"equalLeft"]; } return _leftEqualToView; } - (MarginEqualToView)rightEqualToView { if (!_rightEqualToView) { _rightEqualToView = [self marginEqualToViewBlockWithKey:@"equalRight"]; } return _rightEqualToView; } - (MarginEqualToView)topEqualToView { if (!_topEqualToView) { _topEqualToView = [self marginEqualToViewBlockWithKey:@"equalTop"]; } return _topEqualToView; } - (MarginEqualToView)bottomEqualToView { if (!_bottomEqualToView) { _bottomEqualToView = [self marginEqualToViewBlockWithKey:@"equalBottom"]; } return _bottomEqualToView; } - (MarginEqualToView)centerXEqualToView { if (!_centerXEqualToView) { _centerXEqualToView = [self marginEqualToViewBlockWithKey:@"equalCenterX"]; } return _centerXEqualToView; } - (MarginEqualToView)centerYEqualToView { if (!_centerYEqualToView) { _centerYEqualToView = [self marginEqualToViewBlockWithKey:@"equalCenterY"]; } return _centerYEqualToView; } - (Margin)marginBlockWithKey:(NSString *)key { __weak typeof(self) weakSelf = self; return ^(CGFloat value) { if ([key isEqualToString:@"x"]) { weakSelf.needsAutoResizeView.left_sd = value; } else if ([key isEqualToString:@"y"]) { weakSelf.needsAutoResizeView.top_sd = value; } else if ([key isEqualToString:@"centerX"]) { weakSelf.centerX = @(value); } else if ([key isEqualToString:@"centerY"]) { weakSelf.centerY = @(value); } return weakSelf; }; } - (Margin)xIs { if (!_xIs) { _xIs = [self marginBlockWithKey:@"x"]; } return _xIs; } - (Margin)yIs { if (!_yIs) { _yIs = [self marginBlockWithKey:@"y"]; } return _yIs; } - (Margin)centerXIs { if (!_centerXIs) { _centerXIs = [self marginBlockWithKey:@"centerX"]; } return _centerXIs; } - (Margin)centerYIs { if (!_centerYIs) { _centerYIs = [self marginBlockWithKey:@"centerY"]; } return _centerYIs; } - (AutoHeightWidth)autoHeightRatio { __weak typeof(self) weakSelf = self; if (!_autoHeightRatio) { _autoHeightRatio = ^(CGFloat ratioaValue) { weakSelf.needsAutoResizeView.autoHeightRatioValue = @(ratioaValue); return weakSelf; }; } return _autoHeightRatio; } - (AutoHeightWidth)autoWidthRatio { __weak typeof(self) weakSelf = self; if (!_autoWidthRatio) { _autoWidthRatio = ^(CGFloat ratioaValue) { weakSelf.needsAutoResizeView.autoWidthRatioValue = @(ratioaValue); return weakSelf; }; } return _autoWidthRatio; } - (SpaceToSuperView)spaceToSuperView { __weak typeof(self) weakSelf = self; if (!_spaceToSuperView) { _spaceToSuperView = ^(UIEdgeInsets insets) { UIView *superView = weakSelf.needsAutoResizeView.superview; if (superView) { weakSelf.needsAutoResizeView.sd_layout .leftSpaceToView(superView, insets.left) .topSpaceToView(superView, insets.top) .rightSpaceToView(superView, insets.right) .bottomSpaceToView(superView, insets.bottom); } }; } return _spaceToSuperView; } - (SameWidthHeight)widthEqualToHeight { __weak typeof(self) weakSelf = self; if (!_widthEqualToHeight) { _widthEqualToHeight = ^() { weakSelf.widthEqualHeight = [SDAutoLayoutModelItem new]; weakSelf.lastModelItem = weakSelf.widthEqualHeight; // 主动触发一次赋值操作 weakSelf.needsAutoResizeView.height_sd = weakSelf.needsAutoResizeView.height_sd; return weakSelf; }; } return _widthEqualToHeight; } - (SameWidthHeight)heightEqualToWidth { __weak typeof(self) weakSelf = self; if (!_heightEqualToWidth) { _heightEqualToWidth = ^() { weakSelf.heightEqualWidth = [SDAutoLayoutModelItem new]; weakSelf.lastModelItem = weakSelf.heightEqualWidth; // 主动触发一次赋值操作 weakSelf.needsAutoResizeView.width_sd = weakSelf.needsAutoResizeView.width_sd; return weakSelf; }; } return _heightEqualToWidth; } - (SDAutoLayoutModel *(^)(CGFloat))offset { __weak typeof(self) weakSelf = self; if (!_offset) { _offset = ^(CGFloat offset) { weakSelf.lastModelItem.offset = offset; return weakSelf; }; } return _offset; } @end @implementation UIView (SDAutoHeightWidth) - (SDUIViewCategoryManager *)sd_categoryManager { SDUIViewCategoryManager *manager = objc_getAssociatedObject(self, _cmd); if (!manager) { objc_setAssociatedObject(self, _cmd, [SDUIViewCategoryManager new], OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return objc_getAssociatedObject(self, _cmd); } - (void)setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin { if (!bottomView) return; [self setupAutoHeightWithBottomViewsArray:@[bottomView] bottomMargin:bottomMargin]; } - (void)setupAutoWidthWithRightView:(UIView *)rightView rightMargin:(CGFloat)rightMargin { if (!rightView) return; self.sd_rightViewsArray = @[rightView]; self.sd_rightViewRightMargin = rightMargin; } - (void)setupAutoHeightWithBottomViewsArray:(NSArray *)bottomViewsArray bottomMargin:(CGFloat)bottomMargin { if (!bottomViewsArray) return; // 清空之前的view [self.sd_bottomViewsArray removeAllObjects]; [self.sd_bottomViewsArray addObjectsFromArray:bottomViewsArray]; self.sd_bottomViewBottomMargin = bottomMargin; } - (void)clearAutoHeigtSettings { [self.sd_bottomViewsArray removeAllObjects]; } - (void)clearAutoWidthSettings { self.sd_rightViewsArray = nil; } - (void)updateLayout { [self.superview layoutSubviews]; } - (void)updateLayoutWithCellContentView:(UIView *)cellContentView { if (cellContentView.sd_indexPath) { [cellContentView sd_clearSubviewsAutoLayoutFrameCaches]; } [self updateLayout]; } - (CGFloat)autoHeight { return [objc_getAssociatedObject(self, _cmd) floatValue]; } - (void)setAutoHeight:(CGFloat)autoHeight { objc_setAssociatedObject(self, @selector(autoHeight), @(autoHeight), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSMutableArray *)sd_bottomViewsArray { NSMutableArray *array = objc_getAssociatedObject(self, _cmd); if (!array) { objc_setAssociatedObject(self, _cmd, [NSMutableArray new], OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return objc_getAssociatedObject(self, _cmd); } - (NSArray *)sd_rightViewsArray { return [[self sd_categoryManager] rightViewsArray]; } - (void)setSd_rightViewsArray:(NSArray *)sd_rightViewsArray { [[self sd_categoryManager] setRightViewsArray:sd_rightViewsArray]; } - (CGFloat)sd_bottomViewBottomMargin { return [objc_getAssociatedObject(self, _cmd) floatValue]; } - (void)setSd_bottomViewBottomMargin:(CGFloat)sd_bottomViewBottomMargin { objc_setAssociatedObject(self, @selector(sd_bottomViewBottomMargin), @(sd_bottomViewBottomMargin), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)setSd_rightViewRightMargin:(CGFloat)sd_rightViewRightMargin { [[self sd_categoryManager] setRightViewRightMargin:sd_rightViewRightMargin]; } - (CGFloat)sd_rightViewRightMargin { return [[self sd_categoryManager] rightViewRightMargin]; } @end @implementation UIView (SDLayoutExtention) - (void (^)(CGRect))didFinishAutoLayoutBlock { return objc_getAssociatedObject(self, _cmd); } - (void)setDidFinishAutoLayoutBlock:(void (^)(CGRect))didFinishAutoLayoutBlock { objc_setAssociatedObject(self, @selector(didFinishAutoLayoutBlock), didFinishAutoLayoutBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); } - (NSNumber *)sd_cornerRadius { return objc_getAssociatedObject(self, _cmd); } - (void)setSd_cornerRadius:(NSNumber *)sd_cornerRadius { objc_setAssociatedObject(self, @selector(sd_cornerRadius), sd_cornerRadius, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSNumber *)sd_cornerRadiusFromWidthRatio { return objc_getAssociatedObject(self, _cmd); } - (void)setSd_cornerRadiusFromWidthRatio:(NSNumber *)sd_cornerRadiusFromWidthRatio { objc_setAssociatedObject(self, @selector(sd_cornerRadiusFromWidthRatio), sd_cornerRadiusFromWidthRatio, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSNumber *)sd_cornerRadiusFromHeightRatio { return objc_getAssociatedObject(self, _cmd); } - (void)setSd_cornerRadiusFromHeightRatio:(NSNumber *)sd_cornerRadiusFromHeightRatio { objc_setAssociatedObject(self, @selector(sd_cornerRadiusFromHeightRatio), sd_cornerRadiusFromHeightRatio, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSArray *)sd_equalWidthSubviews { return objc_getAssociatedObject(self, _cmd); } - (void)setSd_equalWidthSubviews:(NSArray *)sd_equalWidthSubviews { objc_setAssociatedObject(self, @selector(sd_equalWidthSubviews), sd_equalWidthSubviews, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)sd_addSubviews:(NSArray *)subviews { [subviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) { if ([view isKindOfClass:[UIView class]]) { [self addSubview:view]; } }]; } @end @implementation UIView (SDAutoFlowItems) - (void)setupAutoWidthFlowItems:(NSArray *)viewsArray withPerRowItemsCount:(NSInteger)perRowItemsCount verticalMargin:(CGFloat)verticalMargin horizontalMargin:(CGFloat)horizontalMagin verticalEdgeInset:(CGFloat)vInset horizontalEdgeInset:(CGFloat)hInset { self.sd_categoryManager.flowItems = viewsArray; self.sd_categoryManager.perRowItemsCount = perRowItemsCount; self.sd_categoryManager.verticalMargin = verticalMargin; self.sd_categoryManager.horizontalMargin = horizontalMagin; self.verticalEdgeInset = vInset; self.horizontalEdgeInset = hInset; self.sd_categoryManager.lastWidth = 0; if (viewsArray.count) { [self setupAutoHeightWithBottomView:viewsArray.lastObject bottomMargin:vInset]; } else { [self clearAutoHeigtSettings]; } } - (void)clearAutoWidthFlowItemsSettings { [self setupAutoWidthFlowItems:nil withPerRowItemsCount:0 verticalMargin:0 horizontalMargin:0 verticalEdgeInset:0 horizontalEdgeInset:0]; } - (void)setupAutoMarginFlowItems:(NSArray *)viewsArray withPerRowItemsCount:(NSInteger)perRowItemsCount itemWidth:(CGFloat)itemWidth verticalMargin:(CGFloat)verticalMargin verticalEdgeInset:(CGFloat)vInset horizontalEdgeInset:(CGFloat)hInset { self.sd_categoryManager.shouldShowAsAutoMarginViews = YES; self.sd_categoryManager.flowItemWidth = itemWidth; [self setupAutoWidthFlowItems:viewsArray withPerRowItemsCount:perRowItemsCount verticalMargin:verticalMargin horizontalMargin:0 verticalEdgeInset:vInset horizontalEdgeInset:hInset]; } - (void)clearAutoMarginFlowItemsSettings { [self setupAutoMarginFlowItems:nil withPerRowItemsCount:0 itemWidth:0 verticalMargin:0 verticalEdgeInset:0 horizontalEdgeInset:0]; } - (void)setHorizontalEdgeInset:(CGFloat)horizontalEdgeInset { self.sd_categoryManager.horizontalEdgeInset = horizontalEdgeInset; } - (CGFloat)horizontalEdgeInset { return self.sd_categoryManager.horizontalEdgeInset; } - (void)setVerticalEdgeInset:(CGFloat)verticalEdgeInset { self.sd_categoryManager.verticalEdgeInset = verticalEdgeInset; } - (CGFloat)verticalEdgeInset { return self.sd_categoryManager.verticalEdgeInset; } @end @implementation UIScrollView (SDAutoContentSize) - (void)setupAutoContentSizeWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin { [self setupAutoHeightWithBottomView:bottomView bottomMargin:bottomMargin]; } - (void)setupAutoContentSizeWithRightView:(UIView *)rightView rightMargin:(CGFloat)rightMargin { if (!rightView) return; self.sd_rightViewsArray = @[rightView]; self.sd_rightViewRightMargin = rightMargin; } @end @implementation UILabel (SDLabelAutoResize) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSArray *selStringsArray = @[@"setText:"]; [selStringsArray enumerateObjectsUsingBlock:^(NSString *selString, NSUInteger idx, BOOL *stop) { NSString *mySelString = [@"sd_" stringByAppendingString:selString]; Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString)); Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString)); method_exchangeImplementations(originalMethod, myMethod); }]; }); } - (void)sd_setText:(NSString *)text { // 如果程序崩溃在这行代码说明是你的label在执行“setText”方法时出了问题而不是在此自动布局库内部出现了问题,请检查你的“setText”方法 [self sd_setText:text]; if (self.sd_maxWidth) { [self sizeToFit]; } else if (self.autoHeightRatioValue) { self.size_sd = CGSizeZero; } } - (BOOL)isAttributedContent { return [objc_getAssociatedObject(self, _cmd) boolValue]; } - (void)setIsAttributedContent:(BOOL)isAttributedContent { objc_setAssociatedObject(self, @selector(isAttributedContent), @(isAttributedContent), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)setSingleLineAutoResizeWithMaxWidth:(CGFloat)maxWidth { self.sd_maxWidth = @(maxWidth); } - (void)setMaxNumberOfLinesToShow:(NSInteger)lineCount { NSAssert(self.ownLayoutModel, @"请在布局完成之后再做此步设置!"); if (lineCount > 0) { if (self.isAttributedContent) { NSDictionary *attrs = [self.attributedText attributesAtIndex:0 effectiveRange:nil]; NSMutableParagraphStyle *paragraphStyle = attrs[NSParagraphStyleAttributeName]; self.sd_layout.maxHeightIs((self.font.lineHeight) * lineCount + paragraphStyle.lineSpacing * (lineCount - 1) + 0.1); } else { self.sd_layout.maxHeightIs(self.font.lineHeight * lineCount + 0.1); } } else { self.sd_layout.maxHeightIs(MAXFLOAT); } } @end @implementation UIButton (SDExtention) - (void)setupAutoSizeWithHorizontalPadding:(CGFloat)hPadding buttonHeight:(CGFloat)buttonHeight { self.fixedHeight = @(buttonHeight); self.titleLabel.sd_layout .leftSpaceToView(self, hPadding) .topEqualToView(self) .heightIs(buttonHeight); [self.titleLabel setSingleLineAutoResizeWithMaxWidth:MAXFLOAT]; [self setupAutoWidthWithRightView:self.titleLabel rightMargin:hPadding]; } @end @implementation SDAutoLayoutModelItem - (instancetype)init { if (self = [super init]) { _offset = 0; } return self; } @end @implementation UIView (SDAutoLayout) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSArray *selStringsArray = @[@"layoutSubviews"]; [selStringsArray enumerateObjectsUsingBlock:^(NSString *selString, NSUInteger idx, BOOL *stop) { NSString *mySelString = [@"sd_" stringByAppendingString:selString]; Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString)); Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString)); method_exchangeImplementations(originalMethod, myMethod); }]; }); } #pragma mark - properties - (NSMutableArray *)autoLayoutModelsArray { if (!objc_getAssociatedObject(self, _cmd)) { objc_setAssociatedObject(self, _cmd, [NSMutableArray array], OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return objc_getAssociatedObject(self, _cmd); } - (NSNumber *)fixedWidth { return objc_getAssociatedObject(self, _cmd); } - (void)setFixedWidth:(NSNumber *)fixedWidth { if (fixedWidth) { self.width_sd = [fixedWidth floatValue]; } objc_setAssociatedObject(self, @selector(fixedWidth), fixedWidth, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSNumber *)fixedHeight { return objc_getAssociatedObject(self, _cmd); } - (void)setFixedHeight:(NSNumber *)fixedHeight { if (fixedHeight) { self.height_sd = [fixedHeight floatValue]; } objc_setAssociatedObject(self, @selector(fixedHeight), fixedHeight, OBJC_ASSOCIATION_RETAIN); } - (NSNumber *)autoHeightRatioValue { return objc_getAssociatedObject(self, _cmd); } - (void)setAutoHeightRatioValue:(NSNumber *)autoHeightRatioValue { objc_setAssociatedObject(self, @selector(autoHeightRatioValue), autoHeightRatioValue, OBJC_ASSOCIATION_RETAIN); } - (NSNumber *)autoWidthRatioValue { return objc_getAssociatedObject(self, _cmd); } - (void)setAutoWidthRatioValue:(NSNumber *)autoWidthRatioValue { objc_setAssociatedObject(self, @selector(autoWidthRatioValue), autoWidthRatioValue, OBJC_ASSOCIATION_RETAIN); } - (NSNumber *)sd_maxWidth { return objc_getAssociatedObject(self, _cmd); } - (void)setSd_maxWidth:(NSNumber *)sd_maxWidth { objc_setAssociatedObject(self, @selector(sd_maxWidth), sd_maxWidth, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)useCellFrameCacheWithIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableview { self.sd_indexPath = indexPath; self.sd_tableView = tableview; } - (UITableView *)sd_tableView { return self.sd_categoryManager.sd_tableView; } - (void)setSd_tableView:(UITableView *)sd_tableView { if ([self isKindOfClass:[UITableViewCell class]]) { [(UITableViewCell *)self contentView].sd_tableView = sd_tableView; } self.sd_categoryManager.sd_tableView = sd_tableView; } - (NSIndexPath *)sd_indexPath { return self.sd_categoryManager.sd_indexPath; } - (void)setSd_indexPath:(NSIndexPath *)sd_indexPath { if ([self isKindOfClass:[UITableViewCell class]]) { [(UITableViewCell *)self contentView].sd_indexPath = sd_indexPath; } self.sd_categoryManager.sd_indexPath = sd_indexPath; } - (SDAutoLayoutModel *)ownLayoutModel { return objc_getAssociatedObject(self, _cmd); } - (void)setOwnLayoutModel:(SDAutoLayoutModel *)ownLayoutModel { objc_setAssociatedObject(self, @selector(ownLayoutModel), ownLayoutModel, OBJC_ASSOCIATION_RETAIN); } - (SDAutoLayoutModel *)sd_layout { #ifdef SDDebugWithAssert /* 卡在这里说明你的要自动布局的view在没有添加到父view的情况下就开始设置布局,你需要这样: 1. UIView *view = [UIView new]; 2. [superView addSubview:view]; 3. view.sd_layout .leftEqualToView()... */ NSAssert(self.superview, @">>>>>>>>>在加入父view之后才可以做自动布局设置"); #endif SDAutoLayoutModel *model = [self ownLayoutModel]; if (!model) { model = [SDAutoLayoutModel new]; model.needsAutoResizeView = self; [self setOwnLayoutModel:model]; [self.superview.autoLayoutModelsArray addObject:model]; } return model; } - (SDAutoLayoutModel *)sd_resetLayout { /* * 方案待定 [self sd_clearAutoLayoutSettings]; return [self sd_layout]; */ SDAutoLayoutModel *model = [self ownLayoutModel]; SDAutoLayoutModel *newModel = [SDAutoLayoutModel new]; newModel.needsAutoResizeView = self; [self sd_clearViewFrameCache]; NSInteger index = 0; if (model) { index = [self.superview.autoLayoutModelsArray indexOfObject:model]; [self.superview.autoLayoutModelsArray replaceObjectAtIndex:index withObject:newModel]; } else { [self.superview.autoLayoutModelsArray addObject:newModel]; } [self setOwnLayoutModel:newModel]; [self sd_clearExtraAutoLayoutItems]; return newModel; } - (SDAutoLayoutModel *)sd_resetNewLayout { [self sd_clearAutoLayoutSettings]; [self sd_clearExtraAutoLayoutItems]; return [self sd_layout]; } - (BOOL)sd_isClosingAutoLayout { return self.sd_categoryManager.sd_isClosingAutoLayout; } - (void)setSd_closeAutoLayout:(BOOL)sd_closeAutoLayout { self.sd_categoryManager.sd_closeAutoLayout = sd_closeAutoLayout; } - (void)removeFromSuperviewAndClearAutoLayoutSettings { [self sd_clearAutoLayoutSettings]; [self removeFromSuperview]; } - (void)sd_clearAutoLayoutSettings { SDAutoLayoutModel *model = [self ownLayoutModel]; if (model) { [self.superview.autoLayoutModelsArray removeObject:model]; [self setOwnLayoutModel:nil]; } [self sd_clearExtraAutoLayoutItems]; } - (void)sd_clearExtraAutoLayoutItems { if (self.autoHeightRatioValue) { self.autoHeightRatioValue = nil; } self.fixedHeight = nil; self.fixedWidth = nil; } - (void)sd_clearViewFrameCache { self.frame = CGRectZero; } - (void)sd_clearSubviewsAutoLayoutFrameCaches { if (self.sd_tableView && self.sd_indexPath) { [self.sd_tableView.cellAutoHeightManager clearHeightCacheOfIndexPaths:@[self.sd_indexPath]]; return; } if (self.autoLayoutModelsArray.count == 0) return; [self.autoLayoutModelsArray enumerateObjectsUsingBlock:^(SDAutoLayoutModel *model, NSUInteger idx, BOOL *stop) { model.needsAutoResizeView.frame = CGRectZero; }]; } - (void)sd_layoutSubviews { // 如果程序崩溃在这行代码说明是你的view在执行“layoutSubvies”方法时出了问题而不是在此自动布局库内部出现了问题,请检查你的“layoutSubvies”方法 [self sd_layoutSubviews]; [self sd_layoutSubviewsHandle]; } - (void)sd_layoutSubviewsHandle{ if (self.sd_equalWidthSubviews.count) { __block CGFloat totalMargin = 0; [self.sd_equalWidthSubviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) { SDAutoLayoutModel *model = view.sd_layout; CGFloat left = model.left ? [model.left.value floatValue] : model.needsAutoResizeView.left_sd; totalMargin += (left + [model.right.value floatValue]); }]; CGFloat averageWidth = (self.width_sd - totalMargin) / self.sd_equalWidthSubviews.count; [self.sd_equalWidthSubviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) { view.width_sd = averageWidth; view.fixedWidth = @(averageWidth); }]; } if (self.sd_categoryManager.flowItems.count && (self.sd_categoryManager.lastWidth != self.width_sd)) { self.sd_categoryManager.lastWidth = self.width_sd; NSInteger perRowItemsCount = self.sd_categoryManager.perRowItemsCount; CGFloat horizontalMargin = 0; CGFloat w = 0; if (self.sd_categoryManager.shouldShowAsAutoMarginViews) { w = self.sd_categoryManager.flowItemWidth; long itemsCount = self.sd_categoryManager.perRowItemsCount; if (itemsCount > 1) { horizontalMargin = (self.width_sd - (self.horizontalEdgeInset * 2) - itemsCount * w) / (itemsCount - 1); } } else { horizontalMargin = self.sd_categoryManager.horizontalMargin; w = (self.width_sd - (self.horizontalEdgeInset * 2) - (perRowItemsCount - 1) * horizontalMargin) / perRowItemsCount; } CGFloat verticalMargin = self.sd_categoryManager.verticalMargin; __block UIView *referencedView = self; [self.sd_categoryManager.flowItems enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) { if (idx < perRowItemsCount) { if (idx == 0) { /* 保留 BOOL shouldShowAsAutoMarginViews = self.sd_categoryManager.shouldShowAsAutoMarginViews; */ view.sd_layout .leftSpaceToView(referencedView, self.horizontalEdgeInset) .topSpaceToView(referencedView, self.verticalEdgeInset) .widthIs(w); } else { view.sd_layout .leftSpaceToView(referencedView, horizontalMargin) .topEqualToView(referencedView) .widthIs(w); } referencedView = view; } else { referencedView = self.sd_categoryManager.flowItems[idx - perRowItemsCount]; view.sd_layout .leftEqualToView(referencedView) .widthIs(w) .topSpaceToView(referencedView, verticalMargin); } }]; } if (self.autoLayoutModelsArray.count) { NSMutableArray *caches = nil; if ([self isKindOfClass:cellContVClass()] && self.sd_tableView) { caches = [self.sd_tableView.cellAutoHeightManager subviewFrameCachesWithIndexPath:self.sd_indexPath]; } [self.autoLayoutModelsArray enumerateObjectsUsingBlock:^(SDAutoLayoutModel *model, NSUInteger idx, BOOL *stop) { if (idx < caches.count) { CGRect originalFrame = model.needsAutoResizeView.frame; CGRect newFrame = [[caches objectAtIndex:idx] CGRectValue]; if (CGRectEqualToRect(originalFrame, newFrame)) { [model.needsAutoResizeView setNeedsLayout]; } else { model.needsAutoResizeView.frame = newFrame; } [self setupCornerRadiusWithView:model.needsAutoResizeView model:model]; model.needsAutoResizeView.sd_categoryManager.hasSetFrameWithCache = YES; } else { if (model.needsAutoResizeView.sd_categoryManager.hasSetFrameWithCache) { model.needsAutoResizeView.sd_categoryManager.hasSetFrameWithCache = NO; } [self sd_resizeWithModel:model]; } }]; } if (self.tag == kSDModelCellTag && [self isKindOfClass:cellContVClass()]) { UITableViewCell *cell = (UITableViewCell *)(self.superview); while (cell && ![cell isKindOfClass:[UITableViewCell class]]) { cell = (UITableViewCell *)cell.superview; } if ([cell isKindOfClass:[UITableViewCell class]]) { CGFloat height = 0; for (UIView *view in cell.sd_bottomViewsArray) { height = MAX(height, view.bottom_sd); } cell.autoHeight = height + cell.sd_bottomViewBottomMargin; } } else if (![self isKindOfClass:[UITableViewCell class]] && (self.sd_bottomViewsArray.count || self.sd_rightViewsArray.count)) { if (self.sd_categoryManager.hasSetFrameWithCache) { self.sd_categoryManager.hasSetFrameWithCache = NO; return; } CGFloat contentHeight = 0; CGFloat contentWidth = 0; if (self.sd_bottomViewsArray) { CGFloat height = 0; for (UIView *view in self.sd_bottomViewsArray) { height = MAX(height, view.bottom_sd); } contentHeight = height + self.sd_bottomViewBottomMargin; } if (self.sd_rightViewsArray) { CGFloat width = 0; for (UIView *view in self.sd_rightViewsArray) { width = MAX(width, view.right_sd); } contentWidth = width + self.sd_rightViewRightMargin; } if ([self isKindOfClass:[UIScrollView class]]) { UIScrollView *scrollView = (UIScrollView *)self; CGSize contentSize = scrollView.contentSize; if (contentHeight > 0) { contentSize.height = contentHeight; } if (contentWidth > 0) { contentSize.width = contentWidth; } if (contentSize.width <= 0) { contentSize.width = scrollView.width_sd; } if (!CGSizeEqualToSize(contentSize, scrollView.contentSize)) { scrollView.contentSize = contentSize; } } else { // 如果这里出现循环调用情况请把demo发送到gsdios@126.com,谢谢配合。 if (self.sd_bottomViewsArray.count && (floorf(contentHeight) != floorf(self.height_sd))) { self.height_sd = contentHeight; self.fixedHeight = @(self.height_sd); } if (self.sd_rightViewsArray.count && (floorf(contentWidth) != floorf(self.width_sd))) { self.width_sd = contentWidth; self.fixedWidth = @(self.width_sd); } } SDAutoLayoutModel *model = self.ownLayoutModel; if (![self isKindOfClass:[UIScrollView class]] && self.sd_rightViewsArray.count && (model.right || model.equalRight || model.centerX || model.equalCenterX)) { self.fixedWidth = @(self.width); if (model.right || model.equalRight) { [self layoutRightWithView:self model:model]; } else { [self layoutLeftWithView:self model:model]; } self.fixedWidth = nil; } if (![self isKindOfClass:[UIScrollView class]] && self.sd_bottomViewsArray.count && (model.bottom || model.equalBottom || model.centerY || model.equalCenterY)) { self.fixedHeight = @(self.height); if (model.bottom || model.equalBottom) { [self layoutBottomWithView:self model:model]; } else { [self layoutTopWithView:self model:model]; } self.fixedHeight = nil; } if (self.didFinishAutoLayoutBlock) { self.didFinishAutoLayoutBlock(self.frame); } } } - (void)sd_resizeWithModel:(SDAutoLayoutModel *)model { UIView *view = model.needsAutoResizeView; if (!view || view.sd_isClosingAutoLayout) return; if (view.sd_maxWidth && (model.rightSpaceToView || model.rightEqualToView)) { // 靠右布局前提设置 [self layoutAutoWidthWidthView:view model:model]; view.fixedWidth = @(view.width_sd); } [self layoutWidthWithView:view model:model]; [self layoutHeightWithView:view model:model]; [self layoutLeftWithView:view model:model]; [self layoutRightWithView:view model:model]; if (view.autoHeightRatioValue && view.width_sd > 0 && (model.bottomEqualToView || model.bottomSpaceToView)) { // 底部布局前提设置 [self layoutAutoHeightWidthView:view model:model]; view.fixedHeight = @(view.height_sd); } if (view.autoWidthRatioValue) { view.fixedWidth = @(view.height_sd * [view.autoWidthRatioValue floatValue]); } [self layoutTopWithView:view model:model]; [self layoutBottomWithView:view model:model]; if ((model.centerX || model.equalCenterX) && !view.fixedWidth) { [self layoutLeftWithView:view model:model]; } if ((model.centerY || model.equalCenterY) && !view.fixedHeight) { [self layoutTopWithView:view model:model]; } if (view.sd_maxWidth) { [self layoutAutoWidthWidthView:view model:model]; } if (model.maxWidth && [model.maxWidth floatValue] < view.width_sd) { view.width_sd = [model.maxWidth floatValue]; } if (model.minWidth && [model.minWidth floatValue] > view.width_sd) { view.width_sd = [model.minWidth floatValue]; } if (view.autoHeightRatioValue && view.width_sd > 0) { [self layoutAutoHeightWidthView:view model:model]; } if (model.maxHeight && [model.maxHeight floatValue] < view.height_sd) { view.height_sd = [model.maxHeight floatValue]; } if (model.minHeight && [model.minHeight floatValue] > view.height_sd) { view.height_sd = [model.minHeight floatValue]; } if (model.widthEqualHeight) { view.width_sd = view.height_sd; } if (model.heightEqualWidth) { view.height_sd = view.width_sd; } if (view.didFinishAutoLayoutBlock) { view.didFinishAutoLayoutBlock(view.frame); } if (view.sd_bottomViewsArray.count || view.sd_rightViewsArray.count) { [view layoutSubviews]; } [self setupCornerRadiusWithView:view model:model]; } - (void)layoutAutoHeightWidthView:(UIView *)view model:(SDAutoLayoutModel *)model { if ([view.autoHeightRatioValue floatValue] > 0) { view.height_sd = view.width_sd * [view.autoHeightRatioValue floatValue]; } else { if ([view isKindOfClass:[UILabel class]]) { UILabel *label = (UILabel *)view; label.numberOfLines = 0; if (label.text.length) { if (!label.isAttributedContent) { CGRect rect = [label.text boundingRectWithSize:CGSizeMake(label.width_sd, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : label.font} context:nil]; label.height_sd = rect.size.height + 0.1; } else { [label sizeToFit]; if (label.sd_maxWidth && label.width_sd > [label.sd_maxWidth floatValue]) { label.width_sd = [label.sd_maxWidth floatValue]; } } } else { label.height_sd = 0; } } else { view.height_sd = 0; } } } - (void)layoutAutoWidthWidthView:(UIView *)view model:(SDAutoLayoutModel *)model { if ([view isKindOfClass:[UILabel class]]) { UILabel *label = (UILabel *)view; CGFloat width = [view.sd_maxWidth floatValue] > 0 ? [view.sd_maxWidth floatValue] : MAXFLOAT; label.numberOfLines = 1; if (label.text.length) { if (!label.isAttributedContent) { CGRect rect = [label.text boundingRectWithSize:CGSizeMake(MAXFLOAT, label.height_sd) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : label.font} context:nil]; if (rect.size.width > width) { rect.size.width = width; } label.width_sd = rect.size.width + 0.1; } else{ [label sizeToFit]; if (label.width_sd > width) { label.width_sd = width; } } } else { label.size_sd = CGSizeZero; } } } - (void)layoutWidthWithView:(UIView *)view model:(SDAutoLayoutModel *)model { if (model.width) { view.width_sd = [model.width.value floatValue]; view.fixedWidth = @(view.width_sd); } else if (model.ratio_width) { view.width_sd = model.ratio_width.refView.width_sd * [model.ratio_width.value floatValue]; view.fixedWidth = @(view.width_sd); } } - (void)layoutHeightWithView:(UIView *)view model:(SDAutoLayoutModel *)model { if (model.height) { view.height_sd = [model.height.value floatValue]; view.fixedHeight = @(view.height_sd); } else if (model.ratio_height) { view.height_sd = [model.ratio_height.value floatValue] * model.ratio_height.refView.height_sd; view.fixedHeight = @(view.height_sd); } } - (void)layoutLeftWithView:(UIView *)view model:(SDAutoLayoutModel *)model { if (model.left) { if (view.superview == model.left.refView) { if (!view.fixedWidth) { // view.autoLeft && view.autoRight view.width_sd = view.right_sd - [model.left.value floatValue]; } view.left_sd = [model.left.value floatValue]; } else { if (model.left.refViewsArray.count) { CGFloat lastRefRight = 0; for (UIView *ref in model.left.refViewsArray) { if ([ref isKindOfClass:[UIView class]] && ref.right_sd > lastRefRight) { model.left.refView = ref; lastRefRight = ref.right_sd; } } } if (!view.fixedWidth) { // view.autoLeft && view.autoRight view.width_sd = view.right_sd - model.left.refView.right_sd - [model.left.value floatValue]; } view.left_sd = model.left.refView.right_sd + [model.left.value floatValue]; } } else if (model.equalLeft) { if (!view.fixedWidth) { if (model.needsAutoResizeView == view.superview) { view.width_sd = view.right_sd - (0 + model.equalLeft.offset); } else { view.width_sd = view.right_sd - (model.equalLeft.refView.left_sd + model.equalLeft.offset); } } if (view.superview == model.equalLeft.refView) { view.left_sd = 0 + model.equalLeft.offset; } else { view.left_sd = model.equalLeft.refView.left_sd + model.equalLeft.offset; } } else if (model.equalCenterX) { if (view.superview == model.equalCenterX.refView) { view.centerX_sd = model.equalCenterX.refView.width_sd * 0.5 + model.equalCenterX.offset; } else { view.centerX_sd = model.equalCenterX.refView.centerX_sd + model.equalCenterX.offset; } } else if (model.centerX) { view.centerX_sd = [model.centerX floatValue]; } } - (void)layoutRightWithView:(UIView *)view model:(SDAutoLayoutModel *)model { if (model.right) { if (view.superview == model.right.refView) { if (!view.fixedWidth) { // view.autoLeft && view.autoRight view.width_sd = model.right.refView.width_sd - view.left_sd - [model.right.value floatValue]; } view.right_sd = model.right.refView.width_sd - [model.right.value floatValue]; } else { if (!view.fixedWidth) { // view.autoLeft && view.autoRight view.width_sd = model.right.refView.left_sd - view.left_sd - [model.right.value floatValue]; } view.right_sd = model.right.refView.left_sd - [model.right.value floatValue]; } } else if (model.equalRight) { if (!view.fixedWidth) { if (model.equalRight.refView == view.superview) { view.width_sd = model.equalRight.refView.width_sd - view.left_sd + model.equalRight.offset; } else { view.width_sd = model.equalRight.refView.right_sd - view.left_sd + model.equalRight.offset; } } view.right_sd = model.equalRight.refView.right_sd + model.equalRight.offset; if (view.superview == model.equalRight.refView) { view.right_sd = model.equalRight.refView.width_sd + model.equalRight.offset; } } } - (void)layoutTopWithView:(UIView *)view model:(SDAutoLayoutModel *)model { if (model.top) { if (view.superview == model.top.refView) { if (!view.fixedHeight) { // view.autoTop && view.autoBottom && view.bottom view.height_sd = view.bottom_sd - [model.top.value floatValue]; } view.top_sd = [model.top.value floatValue]; } else { if (model.top.refViewsArray.count) { CGFloat lastRefBottom = 0; for (UIView *ref in model.top.refViewsArray) { if ([ref isKindOfClass:[UIView class]] && ref.bottom_sd > lastRefBottom) { model.top.refView = ref; lastRefBottom = ref.bottom_sd; } } } if (!view.fixedHeight) { // view.autoTop && view.autoBottom && view.bottom view.height_sd = view.bottom_sd - model.top.refView.bottom_sd - [model.top.value floatValue]; } view.top_sd = model.top.refView.bottom_sd + [model.top.value floatValue]; } } else if (model.equalTop) { if (view.superview == model.equalTop.refView) { if (!view.fixedHeight) { view.height_sd = view.bottom_sd - model.equalTop.offset; } view.top_sd = 0 + model.equalTop.offset; } else { if (!view.fixedHeight) { view.height_sd = view.bottom_sd - (model.equalTop.refView.top_sd + model.equalTop.offset); } view.top_sd = model.equalTop.refView.top_sd + model.equalTop.offset; } } else if (model.equalCenterY) { if (view.superview == model.equalCenterY.refView) { view.centerY_sd = model.equalCenterY.refView.height_sd * 0.5 + model.equalCenterY.offset; } else { view.centerY_sd = model.equalCenterY.refView.centerY_sd + model.equalCenterY.offset; } } else if (model.centerY) { view.centerY_sd = [model.centerY floatValue]; } } - (void)layoutBottomWithView:(UIView *)view model:(SDAutoLayoutModel *)model { if (model.bottom) { if (view.superview == model.bottom.refView) { if (!view.fixedHeight) { view.height_sd = view.superview.height_sd - view.top_sd - [model.bottom.value floatValue]; } view.bottom_sd = model.bottom.refView.height_sd - [model.bottom.value floatValue]; } else { if (!view.fixedHeight) { view.height_sd = model.bottom.refView.top_sd - view.top_sd - [model.bottom.value floatValue]; } view.bottom_sd = model.bottom.refView.top_sd - [model.bottom.value floatValue]; } } else if (model.equalBottom) { if (view.superview == model.equalBottom.refView) { if (!view.fixedHeight) { view.height_sd = view.superview.height_sd - view.top_sd + model.equalBottom.offset; } view.bottom_sd = model.equalBottom.refView.height_sd + model.equalBottom.offset; } else { if (!view.fixedHeight) { view.height_sd = model.equalBottom.refView.bottom_sd - view.top_sd + model.equalBottom.offset; } view.bottom_sd = model.equalBottom.refView.bottom_sd + model.equalBottom.offset; } } if (model.widthEqualHeight && !view.fixedHeight) { [self layoutRightWithView:view model:model]; } } - (void)setupCornerRadiusWithView:(UIView *)view model:(SDAutoLayoutModel *)model { CGFloat cornerRadius = view.layer.cornerRadius; CGFloat newCornerRadius = 0; if (view.sd_cornerRadius && (cornerRadius != [view.sd_cornerRadius floatValue])) { newCornerRadius = [view.sd_cornerRadius floatValue]; } else if (view.sd_cornerRadiusFromWidthRatio && (cornerRadius != [view.sd_cornerRadiusFromWidthRatio floatValue] * view.width_sd)) { newCornerRadius = view.width_sd * [view.sd_cornerRadiusFromWidthRatio floatValue]; } else if (view.sd_cornerRadiusFromHeightRatio && (cornerRadius != view.height_sd * [view.sd_cornerRadiusFromHeightRatio floatValue])) { newCornerRadius = view.height_sd * [view.sd_cornerRadiusFromHeightRatio floatValue]; } if (newCornerRadius > 0) { view.layer.cornerRadius = newCornerRadius; view.clipsToBounds = YES; } } - (void)addAutoLayoutModel:(SDAutoLayoutModel *)model { [self.autoLayoutModelsArray addObject:model]; } @end @implementation UIButton (SDAutoLayoutButton) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSString *selString = @"layoutSubviews"; NSString *mySelString = [@"sd_button_" stringByAppendingString:selString]; Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString)); Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString)); method_exchangeImplementations(originalMethod, myMethod); }); } - (void)sd_button_layoutSubviews { // 如果程序崩溃在这行代码说明是你的view在执行“layoutSubvies”方法时出了问题而不是在此自动布局库内部出现了问题,请检查你的“layoutSubvies”方法 [self sd_button_layoutSubviews]; [self sd_layoutSubviewsHandle]; } @end @implementation UIView (SDChangeFrame) - (BOOL)shouldReadjustFrameBeforeStoreCache { return self.sd_categoryManager.shouldReadjustFrameBeforeStoreCache; } - (void)setShouldReadjustFrameBeforeStoreCache:(BOOL)shouldReadjustFrameBeforeStoreCache { self.sd_categoryManager.shouldReadjustFrameBeforeStoreCache = shouldReadjustFrameBeforeStoreCache; } - (CGFloat)left_sd { return self.frame.origin.x; } - (void)setLeft_sd:(CGFloat)x_sd { CGRect frame = self.frame; frame.origin.x = x_sd; self.frame = frame; } - (CGFloat)top_sd { return self.frame.origin.y; } - (void)setTop_sd:(CGFloat)y_sd { CGRect frame = self.frame; frame.origin.y = y_sd; self.frame = frame; } - (CGFloat)right_sd { return self.frame.origin.x + self.frame.size.width; } - (void)setRight_sd:(CGFloat)right_sd { CGRect frame = self.frame; frame.origin.x = right_sd - frame.size.width; self.frame = frame; } - (CGFloat)bottom_sd { return self.frame.origin.y + self.frame.size.height; } - (void)setBottom_sd:(CGFloat)bottom_sd { CGRect frame = self.frame; frame.origin.y = bottom_sd - frame.size.height; self.frame = frame; } - (CGFloat)centerX_sd { return self.left_sd + self.width_sd * 0.5; } - (void)setCenterX_sd:(CGFloat)centerX_sd { self.left_sd = centerX_sd - self.width_sd * 0.5; } - (CGFloat)centerY_sd { return self.top_sd + self.height_sd * 0.5; } - (void)setCenterY_sd:(CGFloat)centerY_sd { self.top_sd = centerY_sd - self.height_sd * 0.5; } - (CGFloat)width_sd { return self.frame.size.width; } - (void)setWidth_sd:(CGFloat)width_sd { if (self.ownLayoutModel.widthEqualHeight) { if (width_sd != self.height_sd) return; } [self setWidth:width_sd]; if (self.ownLayoutModel.heightEqualWidth) { self.height_sd = width_sd; } } - (CGFloat)height_sd { return self.frame.size.height; } - (void)setHeight_sd:(CGFloat)height_sd { if (self.ownLayoutModel.heightEqualWidth) { if (height_sd != self.width_sd) return; } [self setHeight:height_sd]; if (self.ownLayoutModel.widthEqualHeight) { self.width_sd = height_sd; } } - (CGPoint)origin_sd { return self.frame.origin; } - (void)setOrigin_sd:(CGPoint)origin_sd { CGRect frame = self.frame; frame.origin = origin_sd; self.frame = frame; } - (CGSize)size_sd { return self.frame.size; } - (void)setSize_sd:(CGSize)size_sd { [self setSize:size_sd]; } - (void)setWidth:(CGFloat)width { CGRect frame = self.frame; frame.size.width = width; self.frame = frame; } - (void)setHeight:(CGFloat)height { CGRect frame = self.frame; frame.size.height = height; self.frame = frame; } - (void)setSize:(CGSize)size { CGRect frame = self.frame; frame.size = size; self.frame = frame; } // 兼容旧版本 - (CGFloat)left { return self.left_sd; } - (void)setLeft:(CGFloat)left { self.left_sd = left; } - (CGFloat)right { return self.right_sd; } - (void)setRight:(CGFloat)right { self.right_sd = right; } - (CGFloat)width { return self.width_sd; } - (CGFloat)height { return self.height_sd; } - (CGFloat)top { return self.top_sd; } - (void)setTop:(CGFloat)top { self.top_sd = top; } - (CGFloat)bottom { return self.bottom_sd; } - (void)setBottom:(CGFloat)bottom { self.bottom_sd = bottom; } - (CGFloat)centerX { return self.centerX_sd; } - (void)setCenterX:(CGFloat)centerX { self.centerX_sd = centerX; } - (CGFloat)centerY { return self.centerY_sd; } - (void)setCenterY:(CGFloat)centerY { self.centerY_sd = centerY; } - (CGPoint)origin { return self.origin_sd; } - (void)setOrigin:(CGPoint)origin { self.origin_sd = origin; } - (CGSize)size { return self.size_sd; } @end @implementation SDUIViewCategoryManager @end