子类化 UIButton 支持 spacing 并完美兼容 AutoLayout

众所周知,UIButton 是不支持设置图像和文字间距的。git

网上的文章大多数都是经过调节 titleEdgeInsetsimageEdgeInsets 达到把图像和文字分开的目的,可是这个方法并不能自动改变按钮的大小,因此带来的问题就是调整了间距以后还须要再计算按钮的大小,并且对于 AutoLayout 没法进行自动适应大小。github

要解决这些痛点,比较合适的方式是对 UIButton 子类化,增长一个 spacing 属性,要设置间距就直接改变 spacing 的值就行了,定义以下:布局

@interface ZUIButton : UIButton

@property(nonatomic) CGFloat spacing;

@end
复制代码

由于增长间距后就改变了按钮的大小,因此还须要同时调整 intrinsicContentSizesizeToFit 的实现,这样就能够完美兼容 AutoLayout 和基于 frame 的手动布局:ui

- (CGSize)intrinsicContentSize {
    CGSize size = [super intrinsicContentSize];

    CGSize imageSize = self.currentImage.size;
    if ((self.currentTitle.length > 0 || self.currentAttributedTitle.length > 0) &&
        (imageSize.width > 0 && imageSize.height > 0)) {
        size.width += _spacing;
    }

    return size;
}
复制代码
- (void)sizeToFit {
    [super sizeToFit];

    CGRect bounds = self.bounds;
    bounds.size = [self intrinsicContentSize];
    self.bounds = bounds;

    CGFloat offset = 0;
    CGSize imageSize = self.currentImage.size;
    if ((self.currentTitle.length > 0 || self.currentAttributedTitle.length > 0) &&
        (imageSize.width > 0 && imageSize.height > 0)) {
        offset = _spacing * 0.5;
    }

    CGPoint center = self.center;
    center.x += offset;
    self.center = center;
}
复制代码

这样子类化后的 ZUIButton 就能够很方便经过 spacing 设置间距。atom

再进一步作扩展:支持设置图像和文字的位置。默认状况下按钮只能是图像左文字右的样式,有时候会遇到须要文字左图像右的场景,就没法知足了。spa

继续对 ZUIButton 扩展,支持文字左图像右的显示样式。code

图像和文字的显示区域是由 imageRectForContentRecttitleRectForContentRect 决定的,只要继承这两个方法,在内部调换一下坐标就能够了,很简单。继承

增长一个枚举类型 ZUIButtonDirection 用于设置显示方向:ci

typedef NS_ENUM(NSInteger, ZUIButtonDirection) {
    ZUIButtonDirectionRow = 0,    // 默认样式:图像左,文字右
    ZUIButtonDirectionRowReverse  // 文字左,图像右
};
复制代码

新增一个设置显示方向的属性:directionget

@interface ZUIButton : UIButton

@property(nonatomic) CGFloat spacing;

@property(nonatomic) ZUIButtonDirection direction;

@end
复制代码

根据 direction 的设置从新调整图像和文字的位置:

- (CGRect)imageRectForContentRect:(CGRect)contentRect {
    CGRect rect = [super imageRectForContentRect:contentRect];

    if (_direction == ZUIButtonDirectionRowReverse) {
        CGRect titleRect = [super titleRectForContentRect:contentRect];
        titleRect.origin.x = rect.origin.x;
        rect.origin.x = CGRectGetMaxX(titleRect);
    }

    if (self.currentTitle.length > 0 || self.currentAttributedTitle.length > 0) {
        if (_direction == ZUIButtonDirectionRow) {
            rect.origin.x -= _spacing * 0.5;
        } else if (_direction == ZUIButtonDirectionRowReverse) {
            rect.origin.x += _spacing * 0.5;
        }
    }

    return rect;
}
复制代码
- (CGRect)titleRectForContentRect:(CGRect)contentRect {
    CGRect rect = [super titleRectForContentRect:contentRect];

    if (_direction == ZUIButtonDirectionRowReverse) {
        CGRect imageRect = [super imageRectForContentRect:contentRect];
        rect.origin.x = imageRect.origin.x;
    }

    CGSize imageSize = self.currentImage.size;
    if (imageSize.width > 0 && imageSize.height > 0) {
        if (_direction == ZUIButtonDirectionRow) {
            rect.origin.x += _spacing * 0.5;
        } else if (_direction == ZUIButtonDirectionRowReverse) {
            rect.origin.x -= _spacing * 0.5;
        }
    }

    return rect;
}
复制代码

如今,ZUIButton 用起来就很方便了。

不想把现有项目里的 UIButton 改为 ZUIButton ?来试一下 Method Swizzling 实现的版本,把以上实现作成 UIButton 的分类:

github.com/cntrump/UIB…

相关文章
相关标签/搜索