子類化 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…

相關文章
相關標籤/搜索