//
|
// HDLEZOPButton.m
|
// EZSDK
|
//
|
// Created by Davin on 2023/6/20.
|
//
|
|
#import "HDLEZOPButton.h"
|
|
#define HDLOPScreenScale ([[UIScreen mainScreen] scale])
|
|
#pragma mark - Clang
|
#define ArgumentToString(macro) #macro
|
#define ClangWarningConcat(warning_name) ArgumentToString(clang diagnostic ignored warning_name)
|
/// 参数可直接传入 clang 的 warning 名,warning 列表参考:https://clang.llvm.org/docs/DiagnosticsReference.html
|
#define BeginIgnoreClangWarning(warningName) _Pragma("clang diagnostic push") _Pragma(ClangWarningConcat(#warningName))
|
#define EndIgnoreClangWarning _Pragma("clang diagnostic pop")
|
#define HDLOPBeginIgnorePerformSelectorLeaksWarning BeginIgnoreClangWarning(-Warc-performSelector-leaks)
|
#define HDLOPEndIgnorePerformSelectorLeaksWarning EndIgnoreClangWarning
|
|
#define CGSizeMax CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)
|
|
|
|
CG_INLINE CGFloat
|
removeFloatMin(CGFloat floatValue) {
|
return floatValue == CGFLOAT_MIN ? 0 : floatValue;
|
}
|
|
CG_INLINE CGFloat
|
flatSpecificScale(CGFloat floatValue, CGFloat scale) {
|
floatValue = removeFloatMin(floatValue);
|
scale = scale ?: HDLOPScreenScale;
|
CGFloat flattedValue = ceil(floatValue * scale) / scale;
|
return flattedValue;
|
}
|
|
CG_INLINE CGFloat
|
flat(CGFloat floatValue) {
|
return flatSpecificScale(floatValue, 0);
|
}
|
|
CG_INLINE UIEdgeInsets
|
UIEdgeInsetsRemoveFloatMin(UIEdgeInsets insets) {
|
UIEdgeInsets result = UIEdgeInsetsMake(removeFloatMin(insets.top), removeFloatMin(insets.left), removeFloatMin(insets.bottom), removeFloatMin(insets.right));
|
return result;
|
}
|
|
/// 获取UIEdgeInsets在水平方向上的值
|
CG_INLINE CGFloat
|
UIEdgeInsetsGetHorizontalValue(UIEdgeInsets insets) {
|
return insets.left + insets.right;
|
}
|
|
/// 获取UIEdgeInsets在垂直方向上的值
|
CG_INLINE CGFloat
|
UIEdgeInsetsGetVerticalValue(UIEdgeInsets insets) {
|
return insets.top + insets.bottom;
|
}
|
|
/// 传入size,返回一个x/y为0的CGRect
|
CG_INLINE CGRect
|
CGRectMakeWithSize(CGSize size) {
|
return CGRectMake(0, 0, size.width, size.height);
|
}
|
|
CG_INLINE CGRect
|
CGRectSetX(CGRect rect, CGFloat x) {
|
rect.origin.x = flat(x);
|
return rect;
|
}
|
|
CG_INLINE CGRect
|
CGRectSetY(CGRect rect, CGFloat y) {
|
rect.origin.y = flat(y);
|
return rect;
|
}
|
|
CG_INLINE CGRect
|
CGRectSetXY(CGRect rect, CGFloat x, CGFloat y) {
|
rect.origin.x = flat(x);
|
rect.origin.y = flat(y);
|
return rect;
|
}
|
|
CG_INLINE CGRect
|
CGRectSetWidth(CGRect rect, CGFloat width) {
|
if (width < 0) {
|
return rect;
|
}
|
rect.size.width = flat(width);
|
return rect;
|
}
|
|
CG_INLINE CGRect
|
CGRectSetHeight(CGRect rect, CGFloat height) {
|
if (height < 0) {
|
return rect;
|
}
|
rect.size.height = flat(height);
|
return rect;
|
}
|
|
/// 将一个 CGSize 像素对齐
|
CG_INLINE CGSize
|
CGSizeFlatted(CGSize size) {
|
return CGSizeMake(flat(size.width), flat(size.height));
|
}
|
|
CG_INLINE CGRect
|
CGRectSetSize(CGRect rect, CGSize size) {
|
rect.size = CGSizeFlatted(size);
|
return rect;
|
}
|
|
|
/// 用于居中运算
|
CG_INLINE CGFloat
|
CGFloatGetCenter(CGFloat parent, CGFloat child) {
|
return flat((parent - child) / 2.0);
|
}
|
|
/// 对CGRect的x/y、width/height都调用一次flat,以保证像素对齐
|
CG_INLINE CGRect
|
CGRectFlatted(CGRect rect) {
|
return CGRectMake(flat(rect.origin.x), flat(rect.origin.y), flat(rect.size.width), flat(rect.size.height));
|
}
|
|
/// 判断一个 CGSize 是否为空(宽或高为0)
|
CG_INLINE BOOL
|
CGSizeIsEmpty(CGSize size) {
|
return size.width <= 0 || size.height <= 0;
|
}
|
|
const CGFloat HDLOPButtonCornerRadiusAdjustsBounds = -1;
|
|
@interface HDLEZOPButton ()
|
|
@property(nonatomic, strong) CALayer *highlightedBackgroundLayer;
|
@property(nonatomic, strong) UIColor *originBorderColor;
|
@end
|
|
@implementation HDLEZOPButton
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame {
|
if (self = [super initWithFrame:frame]) {
|
self.tintColor = HDLEZHEXCOLOR(0x5C62FE,0.1);
|
[self setTitleColor:self.tintColor forState:UIControlStateNormal];// 初始化时 adjustsTitleTintColorAutomatically 还是 NO,所以这里手动把 titleColor 设置为 tintColor 的值
|
|
// iOS7以后的button,sizeToFit后默认会自带一个上下的contentInsets,为了保证按钮大小即为内容大小,这里直接去掉,改为一个最小的值。
|
self.contentEdgeInsets = UIEdgeInsetsMake(CGFLOAT_MIN, 0, CGFLOAT_MIN, 0);
|
|
// 放在后面,让前面的默认值可以被子类重写的 didInitialize 覆盖
|
[self didInitialize];
|
}
|
return self;
|
}
|
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
if (self = [super initWithCoder:aDecoder]) {
|
[self didInitialize];
|
}
|
return self;
|
}
|
|
- (void)didInitialize {
|
// 默认接管highlighted和disabled的表现,去掉系统默认的表现
|
self.adjustsImageWhenHighlighted = NO;
|
self.adjustsImageWhenDisabled = NO;
|
self.adjustsButtonWhenHighlighted = YES;
|
self.adjustsButtonWhenDisabled = YES;
|
|
// 图片默认在按钮左边,与系统UIButton保持一致
|
self.imagePosition = HDLEZOPButtonImagePositionLeft;
|
}
|
|
// 系统访问 self.imageView 会触发 layout,而私有方法 _imageView 则是简单地访问 imageView,所以在 HDLOPButton layoutSubviews 里应该用这个方法
|
- (UIImageView *)_hdlop_imageView {
|
HDLOPBeginIgnorePerformSelectorLeaksWarning
|
return [self performSelector:NSSelectorFromString(@"_imageView")];
|
HDLOPEndIgnorePerformSelectorLeaksWarning
|
}
|
|
- (CGSize)sizeThatFits:(CGSize)size {
|
// 如果调用 sizeToFit,那么传进来的 size 就是当前按钮的 size,此时的计算不要去限制宽高
|
// 系统 UIButton 不管任何时候,对 sizeThatFits:CGSizeZero 都会返回真实的内容大小,这里对齐
|
if (CGSizeEqualToSize(self.bounds.size, size) || CGSizeIsEmpty(size)) {
|
size = CGSizeMax;
|
}
|
|
BOOL isImageViewShowing = !!self.currentImage;
|
BOOL isTitleLabelShowing = !!self.currentTitle || self.currentAttributedTitle;
|
CGSize imageTotalSize = CGSizeZero;// 包含 imageEdgeInsets 那些空间
|
CGSize titleTotalSize = CGSizeZero;// 包含 titleEdgeInsets 那些空间
|
CGFloat spacingBetweenImageAndTitle = flat(isImageViewShowing && isTitleLabelShowing ? self.spacingBetweenImageAndTitle : 0);// 如果图片或文字某一者没显示,则这个 spacing 不考虑进布局
|
UIEdgeInsets contentEdgeInsets = UIEdgeInsetsRemoveFloatMin(self.contentEdgeInsets);
|
CGSize resultSize = CGSizeZero;
|
CGSize contentLimitSize = CGSizeMake(size.width - UIEdgeInsetsGetHorizontalValue(contentEdgeInsets), size.height - UIEdgeInsetsGetVerticalValue(contentEdgeInsets));
|
|
switch (self.imagePosition) {
|
case HDLEZOPButtonImagePositionTop:
|
case HDLEZOPButtonImagePositionBottom: {
|
// 图片和文字上下排版时,宽度以文字或图片的最大宽度为最终宽度
|
if (isImageViewShowing) {
|
CGFloat imageLimitWidth = contentLimitSize.width - UIEdgeInsetsGetHorizontalValue(self.imageEdgeInsets);
|
CGSize imageSize = self.imageView.image ? [self.imageView sizeThatFits:CGSizeMake(imageLimitWidth, CGFLOAT_MAX)] : self.currentImage.size;
|
imageSize.width = MIN(imageSize.width, imageLimitWidth);// HDLOPButton sizeThatFits 时 self._imageView 为 nil 但 self.imageView 有值,而开启了 Bold Text 时,系统的 self.imageView sizeThatFits 返回值会比没开启 BoldText 时多 1pt(不知道为什么文字加粗与否会影响 imageView...),从而保证开启 Bold Text 后文字依然能完整展示出来,所以这里应该用 self.imageView 而不是 self._imageView
|
imageTotalSize = CGSizeMake(imageSize.width + UIEdgeInsetsGetHorizontalValue(self.imageEdgeInsets), imageSize.height + UIEdgeInsetsGetVerticalValue(self.imageEdgeInsets));
|
}
|
|
if (isTitleLabelShowing) {
|
CGSize titleLimitSize = CGSizeMake(contentLimitSize.width - UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets), contentLimitSize.height - imageTotalSize.height - spacingBetweenImageAndTitle - UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
CGSize titleSize = [self.titleLabel sizeThatFits:titleLimitSize];
|
titleSize.height = MIN(titleSize.height, titleLimitSize.height);
|
titleTotalSize = CGSizeMake(titleSize.width + UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets), titleSize.height + UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
}
|
|
resultSize.width = UIEdgeInsetsGetHorizontalValue(contentEdgeInsets);
|
resultSize.width += MAX(imageTotalSize.width, titleTotalSize.width);
|
resultSize.height = UIEdgeInsetsGetVerticalValue(contentEdgeInsets) + imageTotalSize.height + spacingBetweenImageAndTitle + titleTotalSize.height;
|
}
|
break;
|
|
case HDLEZOPButtonImagePositionLeft:
|
case HDLEZOPButtonImagePositionRight: {
|
// 图片和文字水平排版时,高度以文字或图片的最大高度为最终高度
|
// 注意这里有一个和系统不一致的行为:当 titleLabel 为多行时,系统的 sizeThatFits: 计算结果固定是单行的,所以当 HDLOPButtonImagePositionLeft 并且titleLabel 多行的情况下,HDLOPButton 计算的结果与系统不一致
|
|
if (isImageViewShowing) {
|
CGFloat imageLimitHeight = contentLimitSize.height - UIEdgeInsetsGetVerticalValue(self.imageEdgeInsets);
|
CGSize imageSize = self.imageView.image ? [self.imageView sizeThatFits:CGSizeMake(CGFLOAT_MAX, imageLimitHeight)] : self.currentImage.size;
|
imageSize.height = MIN(imageSize.height, imageLimitHeight);// HDLOPButton sizeThatFits 时 self._imageView 为 nil 但 self.imageView 有值,而开启了 Bold Text 时,系统的 self.imageView sizeThatFits 返回值会比没开启 BoldText 时多 1pt(不知道为什么文字加粗与否会影响 imageView...),从而保证开启 Bold Text 后文字依然能完整展示出来,所以这里应该用 self.imageView 而不是 self._imageView
|
imageTotalSize = CGSizeMake(imageSize.width + UIEdgeInsetsGetHorizontalValue(self.imageEdgeInsets), imageSize.height + UIEdgeInsetsGetVerticalValue(self.imageEdgeInsets));
|
}
|
|
if (isTitleLabelShowing) {
|
CGSize titleLimitSize = CGSizeMake(contentLimitSize.width - UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets) - imageTotalSize.width - spacingBetweenImageAndTitle, contentLimitSize.height - UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
CGSize titleSize = [self.titleLabel sizeThatFits:titleLimitSize];
|
titleSize.height = MIN(titleSize.height, titleLimitSize.height);
|
titleTotalSize = CGSizeMake(titleSize.width + UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets), titleSize.height + UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
}
|
|
resultSize.width = UIEdgeInsetsGetHorizontalValue(contentEdgeInsets) + imageTotalSize.width + spacingBetweenImageAndTitle + titleTotalSize.width;
|
resultSize.height = UIEdgeInsetsGetVerticalValue(contentEdgeInsets);
|
resultSize.height += MAX(imageTotalSize.height, titleTotalSize.height);
|
}
|
break;
|
}
|
return resultSize;
|
}
|
|
- (CGSize)intrinsicContentSize {
|
return [self sizeThatFits:CGSizeMax];
|
}
|
|
- (void)layoutSubviews {
|
[super layoutSubviews];
|
|
if (CGRectIsEmpty(self.bounds)) {
|
return;
|
}
|
|
if (self.cornerRadius == HDLOPButtonCornerRadiusAdjustsBounds) {
|
self.layer.cornerRadius = CGRectGetHeight(self.bounds) / 2;
|
}
|
|
BOOL isImageViewShowing = !!self.currentImage;
|
BOOL isTitleLabelShowing = !!self.currentTitle || !!self.currentAttributedTitle;
|
CGSize imageLimitSize = CGSizeZero;
|
CGSize titleLimitSize = CGSizeZero;
|
CGSize imageTotalSize = CGSizeZero;// 包含 imageEdgeInsets 那些空间
|
CGSize titleTotalSize = CGSizeZero;// 包含 titleEdgeInsets 那些空间
|
CGFloat spacingBetweenImageAndTitle = flat(isImageViewShowing && isTitleLabelShowing ? self.spacingBetweenImageAndTitle : 0);// 如果图片或文字某一者没显示,则这个 spacing 不考虑进布局
|
CGRect imageFrame = CGRectZero;
|
CGRect titleFrame = CGRectZero;
|
UIEdgeInsets contentEdgeInsets = UIEdgeInsetsRemoveFloatMin(self.contentEdgeInsets);
|
CGSize contentSize = CGSizeMake(CGRectGetWidth(self.bounds) - UIEdgeInsetsGetHorizontalValue(contentEdgeInsets), CGRectGetHeight(self.bounds) - UIEdgeInsetsGetVerticalValue(contentEdgeInsets));
|
|
// 图片的布局原则都是尽量完整展示,所以不管 imagePosition 的值是什么,这个计算过程都是相同的
|
if (isImageViewShowing) {
|
imageLimitSize = CGSizeMake(contentSize.width - UIEdgeInsetsGetHorizontalValue(self.imageEdgeInsets), contentSize.height - UIEdgeInsetsGetVerticalValue(self.imageEdgeInsets));
|
CGSize imageSize = self._hdlop_imageView.image ? [self._hdlop_imageView sizeThatFits:imageLimitSize] : self.currentImage.size;
|
imageSize.width = MIN(imageLimitSize.width, imageSize.width);
|
imageSize.height = MIN(imageLimitSize.height, imageSize.height);
|
imageFrame = CGRectMakeWithSize(imageSize);
|
imageTotalSize = CGSizeMake(imageSize.width + UIEdgeInsetsGetHorizontalValue(self.imageEdgeInsets), imageSize.height + UIEdgeInsetsGetVerticalValue(self.imageEdgeInsets));
|
}
|
|
// UIButton 如果本身大小为 (0,0),此时设置一个 imageEdgeInsets 会让 imageView 的 bounds 错误,导致后续 imageView 的 subviews 布局时会产生偏移,因此这里做一次保护
|
void (^makesureBoundsPositive)(UIView *) = ^void(UIView *view) {
|
CGRect bounds = view.bounds;
|
if (CGRectGetMinX(bounds) < 0 || CGRectGetMinY(bounds) < 0) {
|
bounds = CGRectMakeWithSize(bounds.size);
|
view.bounds = bounds;
|
}
|
};
|
if (isImageViewShowing) {
|
makesureBoundsPositive(self._hdlop_imageView);
|
}
|
if (isTitleLabelShowing) {
|
makesureBoundsPositive(self.titleLabel);
|
}
|
|
if (self.imagePosition == HDLEZOPButtonImagePositionTop || self.imagePosition == HDLEZOPButtonImagePositionBottom) {
|
|
if (isTitleLabelShowing) {
|
titleLimitSize = CGSizeMake(contentSize.width - UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets), contentSize.height - imageTotalSize.height - spacingBetweenImageAndTitle - UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
CGSize titleSize = [self.titleLabel sizeThatFits:titleLimitSize];
|
titleSize.width = MIN(titleLimitSize.width, titleSize.width);
|
titleSize.height = MIN(titleLimitSize.height, titleSize.height);
|
titleFrame = CGRectMakeWithSize(titleSize);
|
titleTotalSize = CGSizeMake(titleSize.width + UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets), titleSize.height + UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
}
|
|
switch (self.contentHorizontalAlignment) {
|
case UIControlContentHorizontalAlignmentLeft:
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, contentEdgeInsets.left + self.imageEdgeInsets.left) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, contentEdgeInsets.left + self.titleEdgeInsets.left) : titleFrame;
|
break;
|
case UIControlContentHorizontalAlignmentCenter:
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, contentEdgeInsets.left + self.imageEdgeInsets.left + CGFloatGetCenter(imageLimitSize.width, CGRectGetWidth(imageFrame))) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, contentEdgeInsets.left + self.titleEdgeInsets.left + CGFloatGetCenter(titleLimitSize.width, CGRectGetWidth(titleFrame))) : titleFrame;
|
break;
|
case UIControlContentHorizontalAlignmentRight:
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - self.imageEdgeInsets.right - CGRectGetWidth(imageFrame)) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - self.titleEdgeInsets.right - CGRectGetWidth(titleFrame)) : titleFrame;
|
break;
|
case UIControlContentHorizontalAlignmentFill:
|
if (isImageViewShowing) {
|
imageFrame = CGRectSetX(imageFrame, contentEdgeInsets.left + self.imageEdgeInsets.left);
|
imageFrame = CGRectSetWidth(imageFrame, imageLimitSize.width);
|
}
|
if (isTitleLabelShowing) {
|
titleFrame = CGRectSetX(titleFrame, contentEdgeInsets.left + self.titleEdgeInsets.left);
|
titleFrame = CGRectSetWidth(titleFrame, titleLimitSize.width);
|
}
|
break;
|
default:
|
break;
|
}
|
|
if (self.imagePosition == HDLEZOPButtonImagePositionTop) {
|
switch (self.contentVerticalAlignment) {
|
case UIControlContentVerticalAlignmentTop:
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, contentEdgeInsets.top + self.imageEdgeInsets.top) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, contentEdgeInsets.top + imageTotalSize.height + spacingBetweenImageAndTitle + self.titleEdgeInsets.top) : titleFrame;
|
break;
|
case UIControlContentVerticalAlignmentCenter: {
|
CGFloat contentHeight = imageTotalSize.height + spacingBetweenImageAndTitle + titleTotalSize.height;
|
CGFloat minY = CGFloatGetCenter(contentSize.height, contentHeight) + contentEdgeInsets.top;
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, minY + self.imageEdgeInsets.top) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, minY + imageTotalSize.height + spacingBetweenImageAndTitle + self.titleEdgeInsets.top) : titleFrame;
|
}
|
break;
|
case UIControlContentVerticalAlignmentBottom:
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, CGRectGetHeight(self.bounds) - contentEdgeInsets.bottom - self.titleEdgeInsets.bottom - CGRectGetHeight(titleFrame)) : titleFrame;
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, CGRectGetHeight(self.bounds) - contentEdgeInsets.bottom - titleTotalSize.height - spacingBetweenImageAndTitle - self.imageEdgeInsets.bottom - CGRectGetHeight(imageFrame)) : imageFrame;
|
break;
|
case UIControlContentVerticalAlignmentFill: {
|
if (isImageViewShowing && isTitleLabelShowing) {
|
|
// 同时显示图片和 label 的情况下,图片高度按本身大小显示,剩余空间留给 label
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, contentEdgeInsets.top + self.imageEdgeInsets.top) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, contentEdgeInsets.top + imageTotalSize.height + spacingBetweenImageAndTitle + self.titleEdgeInsets.top) : titleFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetHeight(titleFrame, CGRectGetHeight(self.bounds) - contentEdgeInsets.bottom - self.titleEdgeInsets.bottom - CGRectGetMinY(titleFrame)) : titleFrame;
|
|
} else if (isImageViewShowing) {
|
imageFrame = CGRectSetY(imageFrame, contentEdgeInsets.top + self.imageEdgeInsets.top);
|
imageFrame = CGRectSetHeight(imageFrame, contentSize.height - UIEdgeInsetsGetVerticalValue(self.imageEdgeInsets));
|
} else {
|
titleFrame = CGRectSetY(titleFrame, contentEdgeInsets.top + self.titleEdgeInsets.top);
|
titleFrame = CGRectSetHeight(titleFrame, contentSize.height - UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
}
|
}
|
break;
|
}
|
} else {
|
switch (self.contentVerticalAlignment) {
|
case UIControlContentVerticalAlignmentTop:
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, contentEdgeInsets.top + self.titleEdgeInsets.top) : titleFrame;
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, contentEdgeInsets.top + titleTotalSize.height + spacingBetweenImageAndTitle + self.imageEdgeInsets.top) : imageFrame;
|
break;
|
case UIControlContentVerticalAlignmentCenter: {
|
CGFloat contentHeight = imageTotalSize.height + titleTotalSize.height + spacingBetweenImageAndTitle;
|
CGFloat minY = CGFloatGetCenter(contentSize.height, contentHeight) + contentEdgeInsets.top;
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, minY + self.titleEdgeInsets.top) : titleFrame;
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, minY + titleTotalSize.height + spacingBetweenImageAndTitle + self.imageEdgeInsets.top) : imageFrame;
|
}
|
break;
|
case UIControlContentVerticalAlignmentBottom:
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, CGRectGetHeight(self.bounds) - contentEdgeInsets.bottom - self.imageEdgeInsets.bottom - CGRectGetHeight(imageFrame)) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, CGRectGetHeight(self.bounds) - contentEdgeInsets.bottom - imageTotalSize.height - spacingBetweenImageAndTitle - self.titleEdgeInsets.bottom - CGRectGetHeight(titleFrame)) : titleFrame;
|
break;
|
case UIControlContentVerticalAlignmentFill: {
|
if (isImageViewShowing && isTitleLabelShowing) {
|
|
// 同时显示图片和 label 的情况下,图片高度按本身大小显示,剩余空间留给 label
|
imageFrame = CGRectSetY(imageFrame, CGRectGetHeight(self.bounds) - contentEdgeInsets.bottom - self.imageEdgeInsets.bottom - CGRectGetHeight(imageFrame));
|
titleFrame = CGRectSetY(titleFrame, contentEdgeInsets.top + self.titleEdgeInsets.top);
|
titleFrame = CGRectSetHeight(titleFrame, CGRectGetHeight(self.bounds) - contentEdgeInsets.bottom - imageTotalSize.height - spacingBetweenImageAndTitle - self.titleEdgeInsets.bottom - CGRectGetMinY(titleFrame));
|
|
} else if (isImageViewShowing) {
|
imageFrame = CGRectSetY(imageFrame, contentEdgeInsets.top + self.imageEdgeInsets.top);
|
imageFrame = CGRectSetHeight(imageFrame, contentSize.height - UIEdgeInsetsGetVerticalValue(self.imageEdgeInsets));
|
} else {
|
titleFrame = CGRectSetY(titleFrame, contentEdgeInsets.top + self.titleEdgeInsets.top);
|
titleFrame = CGRectSetHeight(titleFrame, contentSize.height - UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
}
|
}
|
break;
|
}
|
}
|
|
if (isImageViewShowing) {
|
imageFrame = CGRectFlatted(imageFrame);
|
self._hdlop_imageView.frame = imageFrame;
|
}
|
if (isTitleLabelShowing) {
|
titleFrame = CGRectFlatted(titleFrame);
|
self.titleLabel.frame = titleFrame;
|
}
|
|
} else if (self.imagePosition == HDLEZOPButtonImagePositionLeft || self.imagePosition == HDLEZOPButtonImagePositionRight) {
|
|
if (isTitleLabelShowing) {
|
titleLimitSize = CGSizeMake(contentSize.width - UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets) - imageTotalSize.width - spacingBetweenImageAndTitle, contentSize.height - UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
CGSize titleSize = [self.titleLabel sizeThatFits:titleLimitSize];
|
titleSize.width = MIN(titleLimitSize.width, titleSize.width);
|
titleSize.height = MIN(titleLimitSize.height, titleSize.height);
|
titleFrame = CGRectMakeWithSize(titleSize);
|
titleTotalSize = CGSizeMake(titleSize.width + UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets), titleSize.height + UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
}
|
|
switch (self.contentVerticalAlignment) {
|
case UIControlContentVerticalAlignmentTop:
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, contentEdgeInsets.top + self.imageEdgeInsets.top) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, contentEdgeInsets.top + self.titleEdgeInsets.top) : titleFrame;
|
|
break;
|
case UIControlContentVerticalAlignmentCenter:
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, contentEdgeInsets.top + CGFloatGetCenter(contentSize.height, CGRectGetHeight(imageFrame)) + self.imageEdgeInsets.top) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, contentEdgeInsets.top + CGFloatGetCenter(contentSize.height, CGRectGetHeight(titleFrame)) + self.titleEdgeInsets.top) : titleFrame;
|
break;
|
case UIControlContentVerticalAlignmentBottom:
|
imageFrame = isImageViewShowing ? CGRectSetY(imageFrame, CGRectGetHeight(self.bounds) - contentEdgeInsets.bottom - self.imageEdgeInsets.bottom - CGRectGetHeight(imageFrame)) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetY(titleFrame, CGRectGetHeight(self.bounds) - contentEdgeInsets.bottom - self.titleEdgeInsets.bottom - CGRectGetHeight(titleFrame)) : titleFrame;
|
break;
|
case UIControlContentVerticalAlignmentFill:
|
if (isImageViewShowing) {
|
imageFrame = CGRectSetY(imageFrame, contentEdgeInsets.top + self.imageEdgeInsets.top);
|
imageFrame = CGRectSetHeight(imageFrame, contentSize.height - UIEdgeInsetsGetVerticalValue(self.imageEdgeInsets));
|
}
|
if (isTitleLabelShowing) {
|
titleFrame = CGRectSetY(titleFrame, contentEdgeInsets.top + self.titleEdgeInsets.top);
|
titleFrame = CGRectSetHeight(titleFrame, contentSize.height - UIEdgeInsetsGetVerticalValue(self.titleEdgeInsets));
|
}
|
break;
|
}
|
|
if (self.imagePosition == HDLEZOPButtonImagePositionLeft) {
|
switch (self.contentHorizontalAlignment) {
|
case UIControlContentHorizontalAlignmentLeft:
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, contentEdgeInsets.left + self.imageEdgeInsets.left) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, contentEdgeInsets.left + imageTotalSize.width + spacingBetweenImageAndTitle + self.titleEdgeInsets.left) : titleFrame;
|
break;
|
case UIControlContentHorizontalAlignmentCenter: {
|
CGFloat contentWidth = imageTotalSize.width + spacingBetweenImageAndTitle + titleTotalSize.width;
|
CGFloat minX = contentEdgeInsets.left + CGFloatGetCenter(contentSize.width, contentWidth);
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, minX + self.imageEdgeInsets.left) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, minX + imageTotalSize.width + spacingBetweenImageAndTitle + self.titleEdgeInsets.left) : titleFrame;
|
}
|
break;
|
case UIControlContentHorizontalAlignmentRight: {
|
if (imageTotalSize.width + spacingBetweenImageAndTitle + titleTotalSize.width > contentSize.width) {
|
// 图片和文字总宽超过按钮宽度,则优先完整显示图片
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, contentEdgeInsets.left + self.imageEdgeInsets.left) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, contentEdgeInsets.left + imageTotalSize.width + spacingBetweenImageAndTitle + self.titleEdgeInsets.left) : titleFrame;
|
} else {
|
// 内容不超过按钮宽度,则靠右布局即可
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - self.titleEdgeInsets.right - CGRectGetWidth(titleFrame)) : titleFrame;
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - titleTotalSize.width - spacingBetweenImageAndTitle - imageTotalSize.width + self.imageEdgeInsets.left) : imageFrame;
|
}
|
}
|
break;
|
case UIControlContentHorizontalAlignmentFill: {
|
if (isImageViewShowing && isTitleLabelShowing) {
|
// 同时显示图片和 label 的情况下,图片按本身宽度显示,剩余空间留给 label
|
imageFrame = CGRectSetX(imageFrame, contentEdgeInsets.left + self.imageEdgeInsets.left);
|
titleFrame = CGRectSetX(titleFrame, contentEdgeInsets.left + imageTotalSize.width + spacingBetweenImageAndTitle + self.titleEdgeInsets.left);
|
titleFrame = CGRectSetWidth(titleFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - self.titleEdgeInsets.right - CGRectGetMinX(titleFrame));
|
} else if (isImageViewShowing) {
|
imageFrame = CGRectSetX(imageFrame, contentEdgeInsets.left + self.imageEdgeInsets.left);
|
imageFrame = CGRectSetWidth(imageFrame, contentSize.width - UIEdgeInsetsGetHorizontalValue(self.imageEdgeInsets));
|
} else {
|
titleFrame = CGRectSetX(titleFrame, contentEdgeInsets.left + self.titleEdgeInsets.left);
|
titleFrame = CGRectSetWidth(titleFrame, contentSize.width - UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets));
|
}
|
}
|
break;
|
default:
|
break;
|
}
|
} else {
|
switch (self.contentHorizontalAlignment) {
|
case UIControlContentHorizontalAlignmentLeft: {
|
if (imageTotalSize.width + spacingBetweenImageAndTitle + titleTotalSize.width > contentSize.width) {
|
// 图片和文字总宽超过按钮宽度,则优先完整显示图片
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - self.imageEdgeInsets.right - CGRectGetWidth(imageFrame)) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - imageTotalSize.width - spacingBetweenImageAndTitle - titleTotalSize.width + self.titleEdgeInsets.left) : titleFrame;
|
} else {
|
// 内容不超过按钮宽度,则靠左布局即可
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, contentEdgeInsets.left + self.titleEdgeInsets.left) : titleFrame;
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, contentEdgeInsets.left + titleTotalSize.width + spacingBetweenImageAndTitle + self.imageEdgeInsets.left) : imageFrame;
|
}
|
}
|
break;
|
case UIControlContentHorizontalAlignmentCenter: {
|
CGFloat contentWidth = imageTotalSize.width + spacingBetweenImageAndTitle + titleTotalSize.width;
|
CGFloat minX = contentEdgeInsets.left + CGFloatGetCenter(contentSize.width, contentWidth);
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, minX + self.titleEdgeInsets.left) : titleFrame;
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, minX + titleTotalSize.width + spacingBetweenImageAndTitle + self.imageEdgeInsets.left) : imageFrame;
|
}
|
break;
|
case UIControlContentHorizontalAlignmentRight:
|
imageFrame = isImageViewShowing ? CGRectSetX(imageFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - self.imageEdgeInsets.right - CGRectGetWidth(imageFrame)) : imageFrame;
|
titleFrame = isTitleLabelShowing ? CGRectSetX(titleFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - imageTotalSize.width - spacingBetweenImageAndTitle - self.titleEdgeInsets.right - CGRectGetWidth(titleFrame)) : titleFrame;
|
break;
|
case UIControlContentHorizontalAlignmentFill: {
|
if (isImageViewShowing && isTitleLabelShowing) {
|
// 图片按自身大小显示,剩余空间由标题占满
|
imageFrame = CGRectSetX(imageFrame, CGRectGetWidth(self.bounds) - contentEdgeInsets.right - self.imageEdgeInsets.right - CGRectGetWidth(imageFrame));
|
titleFrame = CGRectSetX(titleFrame, contentEdgeInsets.left + self.titleEdgeInsets.left);
|
titleFrame = CGRectSetWidth(titleFrame, CGRectGetMinX(imageFrame) - self.imageEdgeInsets.left - spacingBetweenImageAndTitle - self.titleEdgeInsets.right - CGRectGetMinX(titleFrame));
|
|
} else if (isImageViewShowing) {
|
imageFrame = CGRectSetX(imageFrame, contentEdgeInsets.left + self.imageEdgeInsets.left);
|
imageFrame = CGRectSetWidth(imageFrame, contentSize.width - UIEdgeInsetsGetHorizontalValue(self.imageEdgeInsets));
|
} else {
|
titleFrame = CGRectSetX(titleFrame, contentEdgeInsets.left + self.titleEdgeInsets.left);
|
titleFrame = CGRectSetWidth(titleFrame, contentSize.width - UIEdgeInsetsGetHorizontalValue(self.titleEdgeInsets));
|
}
|
}
|
break;
|
default:
|
break;
|
}
|
}
|
|
if (isImageViewShowing) {
|
imageFrame = CGRectFlatted(imageFrame);
|
self._hdlop_imageView.frame = imageFrame;
|
}
|
if (isTitleLabelShowing) {
|
titleFrame = CGRectFlatted(titleFrame);
|
self.titleLabel.frame = titleFrame;
|
}
|
}
|
}
|
|
- (void)setSpacingBetweenImageAndTitle:(CGFloat)spacingBetweenImageAndTitle {
|
_spacingBetweenImageAndTitle = spacingBetweenImageAndTitle;
|
|
[self setNeedsLayout];
|
}
|
|
- (void)setImagePosition:(HDLEZOPButtonImagePosition)imagePosition {
|
_imagePosition = imagePosition;
|
|
[self setNeedsLayout];
|
}
|
|
- (void)setHighlightedBackgroundColor:(UIColor *)highlightedBackgroundColor {
|
_highlightedBackgroundColor = highlightedBackgroundColor;
|
if (_highlightedBackgroundColor) {
|
// 只要开启了highlightedBackgroundColor,就默认不需要alpha的高亮
|
self.adjustsButtonWhenHighlighted = NO;
|
}
|
}
|
|
- (void)setHighlightedBorderColor:(UIColor *)highlightedBorderColor {
|
_highlightedBorderColor = highlightedBorderColor;
|
if (_highlightedBorderColor) {
|
// 只要开启了highlightedBorderColor,就默认不需要alpha的高亮
|
self.adjustsButtonWhenHighlighted = NO;
|
}
|
}
|
|
- (void)setHighlighted:(BOOL)highlighted {
|
[super setHighlighted:highlighted];
|
|
if (highlighted && !self.originBorderColor) {
|
// 手指按在按钮上会不断触发setHighlighted:,所以这里做了保护,设置过一次就不用再设置了
|
self.originBorderColor = [UIColor colorWithCGColor:self.layer.borderColor];
|
}
|
|
// 渲染背景色
|
// if (self.highlightedBackgroundColor || self.highlightedBorderColor) {
|
// [self adjustsButtonHighlighted];
|
// }
|
// 如果此时是disabled,则disabled的样式优先
|
if (!self.enabled) {
|
return;
|
}
|
// 自定义highlighted样式
|
// if (self.adjustsButtonWhenHighlighted) {
|
// if (highlighted) {
|
// self.alpha = ButtonHighlightedAlpha;
|
// } else {
|
// self.alpha = 1;
|
// }
|
// }
|
}
|
|
- (void)setEnabled:(BOOL)enabled {
|
[super setEnabled:enabled];
|
if (!enabled && self.adjustsButtonWhenDisabled) {
|
// self.alpha = ButtonDisabledAlpha;
|
self.alpha = 1;
|
} else {
|
self.alpha = 1;
|
}
|
}
|
|
//- (void)adjustsButtonHighlighted {
|
// if (self.highlightedBackgroundColor) {
|
// if (!self.highlightedBackgroundLayer) {
|
// self.highlightedBackgroundLayer = [CALayer layer];
|
// [self.highlightedBackgroundLayer qmui_removeDefaultAnimations];
|
// [self.layer insertSublayer:self.highlightedBackgroundLayer atIndex:0];
|
// }
|
// self.highlightedBackgroundLayer.frame = self.bounds;
|
// self.highlightedBackgroundLayer.cornerRadius = self.layer.cornerRadius;
|
// self.highlightedBackgroundLayer.maskedCorners = self.layer.maskedCorners;
|
// self.highlightedBackgroundLayer.backgroundColor = self.highlighted ? self.highlightedBackgroundColor.CGColor : UIColorClear.CGColor;
|
// }
|
//
|
// if (self.highlightedBorderColor) {
|
// self.layer.borderColor = self.highlighted ? self.highlightedBorderColor.CGColor : self.originBorderColor.CGColor;
|
// }
|
//}
|
|
- (void)setAdjustsTitleTintColorAutomatically:(BOOL)adjustsTitleTintColorAutomatically {
|
_adjustsTitleTintColorAutomatically = adjustsTitleTintColorAutomatically;
|
[self updateTitleColorIfNeeded];
|
}
|
|
- (void)updateTitleColorIfNeeded {
|
if (self.adjustsTitleTintColorAutomatically && self.currentTitleColor) {
|
[self setTitleColor:self.tintColor forState:UIControlStateNormal];
|
}
|
if (self.adjustsTitleTintColorAutomatically && self.currentAttributedTitle) {
|
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.currentAttributedTitle];
|
[attributedString addAttribute:NSForegroundColorAttributeName value:self.tintColor range:NSMakeRange(0, attributedString.length)];
|
[self setAttributedTitle:attributedString forState:UIControlStateNormal];
|
}
|
}
|
|
- (void)setAdjustsImageTintColorAutomatically:(BOOL)adjustsImageTintColorAutomatically {
|
BOOL valueDifference = _adjustsImageTintColorAutomatically != adjustsImageTintColorAutomatically;
|
_adjustsImageTintColorAutomatically = adjustsImageTintColorAutomatically;
|
|
if (valueDifference) {
|
[self updateImageRenderingModeIfNeeded];
|
}
|
}
|
|
- (void)updateImageRenderingModeIfNeeded {
|
if (self.currentImage) {
|
NSArray<NSNumber *> *states = @[@(UIControlStateNormal), @(UIControlStateHighlighted), @(UIControlStateSelected), @(UIControlStateSelected|UIControlStateHighlighted), @(UIControlStateDisabled)];
|
|
for (NSNumber *number in states) {
|
UIImage *image = [self imageForState:number.unsignedIntegerValue];
|
if (!image) {
|
continue;
|
}
|
if (number.unsignedIntegerValue != UIControlStateNormal && image == [self imageForState:UIControlStateNormal]) {
|
continue;
|
}
|
|
if (self.adjustsImageTintColorAutomatically) {
|
// 这里的 setImage: 操作不需要使用 renderingMode 对 image 重新处理,而是放到重写的 setImage:forState 里去做就行了
|
[self setImage:image forState:[number unsignedIntegerValue]];
|
} else {
|
// 如果不需要用template的模式渲染,并且之前是使用template的,则把renderingMode改回Original
|
[self setImage:[image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:[number unsignedIntegerValue]];
|
}
|
}
|
}
|
}
|
|
- (void)setImage:(UIImage *)image forState:(UIControlState)state {
|
if (self.adjustsImageTintColorAutomatically) {
|
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
}
|
|
[super setImage:image forState:state];
|
}
|
|
- (void)tintColorDidChange {
|
[super tintColorDidChange];
|
|
[self updateTitleColorIfNeeded];
|
|
if (self.adjustsImageTintColorAutomatically) {
|
[self updateImageRenderingModeIfNeeded];
|
}
|
}
|
|
- (void)setTintColorAdjustsTitleAndImage:(UIColor *)tintColorAdjustsTitleAndImage {
|
_tintColorAdjustsTitleAndImage = tintColorAdjustsTitleAndImage;
|
if (tintColorAdjustsTitleAndImage) {
|
self.tintColor = tintColorAdjustsTitleAndImage;
|
self.adjustsTitleTintColorAutomatically = YES;
|
self.adjustsImageTintColorAutomatically = YES;
|
}
|
}
|
|
- (void)setCornerRadius:(CGFloat)cornerRadius {
|
_cornerRadius = cornerRadius;
|
if (cornerRadius != HDLOPButtonCornerRadiusAdjustsBounds) {
|
self.layer.cornerRadius = cornerRadius;
|
}
|
[self setNeedsLayout];
|
}
|
|
|
@end
|