之前一直對UIButton的圖文混排一直很迷糊,知道可以通過titleEdgeInset和imageEdgeInset屬性來調整,但一直不知道inset的各個值是相對誰的或者說怎么計算的。直到前天看見2篇關于圖文混排的文章參考文章1 和參考文章2,才豁然開朗,然后自己寫代碼實踐并記錄下(它們的比我考慮的情況多,本篇假設button的高寬都足夠容納下文本和圖片的情況)。友情提示:如果不想看計算過程可以直接跳到尾部copy代碼
如后一篇文章里說的的前置知識點:
imageEdgeInsets(top,left,bottom,right) 和 titleEdgeInsets(top,left,bottom,right)的值就是我們想要的最終結果與按鈕初始狀態比較圖片和標題的位置分別在上下左右位移的值
對于各種排版就知道怎么計算titleEdgeInset和imageEdgeInset,下面配合圖文說明就很容易理解了。
當設置好button的圖片和文本后的初始狀態如下:
這個時候是圖片和文本組成的整體是居中于button里的,且圖片在左,文本在右。項目里經常遇到圖片和文本之間有個padding啊,或者圖片在文本上邊,右邊或者下邊的情況。如下圖:
圖片和文本之間只是多了個padding:
這個時候怎么計算titleEdgeInset和imageEdgeInset呢?就是用最終狀態的坐標減去初始狀態的坐標。具體來說,對于imageView,它的垂直坐標沒變,也就是top和bottom都是0,titleLabel也是。imageView的左邊相對于而言往左移動了padding / 2.0,相應的titleLabel 相比原來而言則右移了padding/2.0。算下來就是:
imageEdgeInset = UIEdgeInsetsMake(0, -padding / 2.0, 0, padding / 2.0);
titleEdgeInset = UIEdgeInsetsMake(0, padding / 2.0, 0, -padding / 2.0);
對于圖片在右,文本在左的排版如下圖:
同樣的,imageView和titleLabel的垂直左邊均沒有改變,top和bottom都是0,imageView的左邊相對于其初始狀態向右移動了titleLabel.size.width+padding / 2.0,其左邊自然也相對于其初始狀態左邊右移了titleLabel.size.width+padding / 2.0,titleLabel的左邊相對于初始狀態左邊左移了imageView.size.wdith + padding / 2.0,其右邊自然也相對于其初始狀態右邊左移了imageView.size.wdith + padding / 2.0,計算下來:
imageEdgeInset = UIEdgeInsetsMake(0, titleLabel.frame.size.width + padding / 2.0, 0, -titleLabel.frame.size.width - padding / 2.0);
titleEdgeInset = UIEdgeInsetsMake(0, -imageView.frame.size.width - padding / 2.0, 0, imageView.frame.size.width + padding / 2.0);
對于圖片在上,文本在下的排版如下:
imageView和titleLabel作為一個整體是居中于button里的,因此可以偏移量可以如下計算:
imageEdgeInset.left = button.frame.size.width/ 2.0 - CGRectGetMidX(imageView.frame)//通過他們的水平中心點來計算
titleEdgeInset.left = button.frame.size.width/ 2.0 - CGRectGetMidX(titleLabel.frame)//通過他們的水平中心點來計算
對于top的計算同樣根據最終的坐標減去初始坐標,先計算最終態的imageView.origin.y
y = (button.frame.size.height - imageView.frame.size.height - padding - titleLabel.frame.size.height) / 2.0;
因此:
imageEdgeInset.top = y - imageView.frame.origin.y = (button.frame.size.height - imageView.frame.size.height - padding - titleLabel.frame.size.height) / 2.0 - imageView.frame.origin.y;
同理可以算出titlLabel的top偏移量為
titleEdgeInset.top = y + imageView.frame.size.height + padding - titleLabel.frame.origin.y = (button.frame.size.height - imageView.frame.size.height - padding - titleLabel.frame.size.height) / 2.0 + imageView.frame.size.height + padding - titleLabel.frame.origin.y = button.frame.size.height / 2.0 + imageView.frame.size.height / 2.0 + padding / 2.0 - titleLabel.frame.origin.y;
是時候綜合下了:
imageEdgeInset = UIEdgeInsetsMake(y - imageView.frame.origin.y, button.frame.size.width/ 2.0 - CGRectGetMidX(imageView.frame), -y + imageView.frame.origin.y, -button.frame.size.width/ 2.0 + CGRectGetMidX(imageView.frame));
titleEdgeInset = UIEdgeInsetsMake(y + imageView.frame.size.height + padding - titleLabel.frame.origin.y, button.frame.size.width/ 2.0 - CGRectGetMidX(titleLabel.frame), -(y + imageView.frame.size.height + padding - titleLabel.frame.origin.y), -button.frame.size.width/ 2.0 + CGRectGetMidX(titleLabel.frame));
代碼復制好累,最后一種情況圖片在下,文本在上:
計算思路,同上一種情況一樣,不寫具體的計算代碼了最后總結下自己寫了一個UIButton的分類,有興趣的可以直接拷貝下面這段
typedef NS_ENUM(NSInteger, CPButtonStyle) {
CPButtonStyleDefault = 0,
CPButtonStyleImageUp,
CPButtonStyleImageRight,
CPButtonStyleImageBottom
};
- (void)setButtonStyle:(CPButtonStyle)style imageTitlePadding:(CGFloat)padding {
CGRect tempFrame = self.frame;
UILabel *label = [[UILabel alloc] init]; //為了防止拿不到titleLabel的高寬,新建一個UILabel,獲取高寬
label.font = self.titleLabel.font;
label.text = self.titleLabel.text;
[label sizeToFit];
CGRect titleFrame = label.frame;
UIImageView *imageView = [[UIImageView alloc] init];//為了防止拿不到button的imageView的高寬,新建一個UIImageView,獲取高寬
imageView.image = self.imageView.image;
[imageView sizeToFit];
CGRect imageFrame = imageView.frame;
if (imageFrame.size.width == 0 || imageFrame.size.height == 0 || titleFrame.size.width == 0 || titleFrame.size.height == 0) {
padding = 0;
}
CGRect frame = self.frame;
frame.size.width = SCREEN_WIDTH; //這樣做目的是盡可能顯示下圖片和標題
frame.size.height = SCREEN_HEIGHT;
CGFloat iTop, iLeft, iRight, iBottom;
CGFloat tTop, tLeft, tRight, tBottom;
iTop = iLeft = iRight = iBottom = tTop = tLeft = tRight = tBottom = 0.0;
if (style == CPButtonStyleImageRight) {
iLeft = titleFrame.size.width + padding / 2.0;
tLeft = -imageFrame.size.width - padding / 2.0;
}
if (style == CPButtonStyleImageUp) {
CGFloat temp = (frame.size.height - (titleFrame.size.height + imageFrame.size.height + padding)) / 2.0;
iLeft = frame.size.width / 2.0 - CGRectGetMidX(imageFrame);
iTop = temp - imageFrame.origin.y;
tLeft = frame.size.width / 2.0 - CGRectGetMidX(titleFrame);
tTop = temp + imageFrame.size.height + padding - titleFrame.origin.y;
}
if (style == CPButtonStyleImageBottom) {
CGFloat temp = (frame.size.height - (titleFrame.size.height + imageFrame.size.height + padding)) / 2.0;
iLeft = frame.size.width / 2.0 - CGRectGetMidX(imageFrame);
iTop = temp + titleFrame.size.height + padding - imageFrame.origin.y;
tLeft = frame.size.width / 2.0 - CGRectGetMidX(titleFrame);
tTop = temp - titleFrame.origin.y;
}
if (style == CPButtonStyleDefault) {
iLeft = -padding /2.0;
tLeft = padding / 2.0;
}
iRight = -iLeft;
iBottom = -iTop;
tRight = -tLeft;
tBottom = -tTop;
self.imageEdgeInsets = UIEdgeInsetsMake(iTop, iLeft, iBottom, iRight);
self.titleEdgeInsets = UIEdgeInsetsMake(tTop, tLeft, tBottom, tRight);
if (style == CPButtonStyleImageRight || style == CPButtonStyleDefault) {//設置完后,button的大小為剛好容納圖片和標題的大小,原始的sizeToFit方法不會算入這個padding
tempFrame.size.width = imageFrame.size.width + titleFrame.size.width + padding;
tempFrame.size.height = MAX(imageFrame.size.height, titleFrame.size.height);
} else {
tempFrame.size.width = MAX(imageFrame.size.width, titleFrame.size.width);
tempFrame.size.height = imageFrame.size.width + titleFrame.size.width + padding;
}
self.frame = tempFrame;
}