衆所周知,UIButton
是不支持設置圖像和文字間距的。git
網上的文章大多數都是經過調節 titleEdgeInsets
和 imageEdgeInsets
達到把圖像和文字分開的目的,可是這個方法並不能自動改變按鈕的大小,因此帶來的問題就是調整了間距以後還須要再計算按鈕的大小,並且對於 AutoLayout 沒法進行自動適應大小。github
要解決這些痛點,比較合適的方式是對 UIButton
子類化,增長一個 spacing
屬性,要設置間距就直接改變 spacing
的值就行了,定義以下:佈局
@interface ZUIButton : UIButton
@property(nonatomic) CGFloat spacing;
@end
複製代碼
由於增長間距後就改變了按鈕的大小,因此還須要同時調整 intrinsicContentSize
和 sizeToFit
的實現,這樣就能夠完美兼容 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
圖像和文字的顯示區域是由 imageRectForContentRect
和 titleRectForContentRect
決定的,只要繼承這兩個方法,在內部調換一下座標就能夠了,很簡單。繼承
增長一個枚舉類型 ZUIButtonDirection
用於設置顯示方向:ci
typedef NS_ENUM(NSInteger, ZUIButtonDirection) {
ZUIButtonDirectionRow = 0, // 默認樣式:圖像左,文字右
ZUIButtonDirectionRowReverse // 文字左,圖像右
};
複製代碼
新增一個設置顯示方向的屬性:direction
get
@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
的分類: