创建图文混排并整体居中的UIButton
之前一直对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;
}