2019-10-20
不管是什么应用 UIButton
在项目中的使用都是必不可少的,很多时候我们会同时给 UIButton
添加上 image
和 title
以及在 image
和 title
间留一些间距, 再有时候可能还希望其左边或者是右边留有有一些间距,这样 UI 显得更加美观。可能的布局看起来像这样:
尽管这看起来很容易实现,只要合理的设置 UIButton
的 titleEdgeInsets
、imageEdgeInsets
、contentEdgeInsets
等属性就可以实现这些效果,但是不得不说还是有很多开发者不确定如何控制这几个属性,而导致项目相关的地方出现了一些问题,所以接下来增对个人的理解对这几个属性的设置进行一些说明。
UIButton 中 imageView 与 titleLabel 的布局
在 UIButton
的内部布局中假设有个参考线,imageView
与 titleLabel
的布局均以该参考线为参照左右上下进行偏移,最终实现在 image
与 title
间添加间距 imageTextSpacing
的布局。(注意这里的参考线很重要)
开始举例前的初始代码如下:
let button = UIButton()
var titleInsets = button.titleEdgeInsets
var imageInsets = button.imageEdgeInsets
var contentInsets = button.contentEdgeInsets
var buttonSize = button.sizeThatFits(CGSize.zero)
let imageTextSpacing: CGFloat = 0 // image 与 title 的间距
let titleSize = button.titleLabel!.sizeThatFits(CGSize.zero)
let imageSize = button.imageView!.sizeThatFits(CGSize.zero)
func reset() {
titleInsets = button.titleEdgeInsets
imageInsets = button.imageEdgeInsets
contentInsets = button.contentEdgeInsets
buttonSize = button.sizeThatFits(CGSize.zero)
}
一、 左 image
右 title
的布局
-
左
image
右title
→ 居中对齐 (默认), 参考线为中线 ━━┇━━布局实现:在当前布局上以中线为参考线那么需将
image
左移imageTextSpacing / 2
,title
右移imageTextSpacing / 2
,buttonSize.width
增加imageTextSpacing
即可example(of: "(左 image 右 title) → 居中对齐 (默认) + 间距") { imageInsets.left = -imageTextSpacing / 2.0 imageInsets.right = imageTextSpacing / 2.0 titleInsets.left = imageTextSpacing / 2.0 titleInsets.right = -imageTextSpacing / 2.0 buttonSize.width += imageTextSpacing }
-
左
image
右title
→ 左对齐, 参考线在左侧 ┇━━━━在当前布局上
image
由于默认就是贴近左侧线所以保持不变,title
右移imageTextSpacing
,buttonSize.width
增加imageTextSpacing
即可example(of: "(左 image 右 title) → 左对齐 + 间距") { button.contentHorizontalAlignment = .left titleInsets.left = imageTextSpacing titleInsets.right = -imageTextSpacing imageInsets = UIEdgeInsets.zero buttonSize.width += imageTextSpacing }
-
左
image
右title
→ 右对齐, 参考线在右侧 ┇━━━━在当前布局上
title
由于默认就是贴近右侧所以保持不变,image
左移imageTextSpacing
,buttonSize.width
增加imageTextSpacing
即可example(of: "(左 image 右 title) → 右对齐 + 间距") { button.contentHorizontalAlignment = .right titleInsets = UIEdgeInsets.zero imageInsets.left = -imageTextSpacing imageInsets.right = imageTextSpacing buttonSize.width += imageTextSpacing }
二、 左 title
右 image
的布局
首先需要实现的是左边 title
右边 image
的布局, 然后再添加间距
-
左
title
右image
→ 居中对齐 (默认) + 无间距在初始布局上将
title
左移imageSize.width
,image
右移titleSize.width
即可达到效果example(of: "左 title 右 image → 居中对齐 (默认) + 无间距") { titleInsets.left = -imageSize.width titleInsets.right = imageSize.width imageInsets.left = titleSize.width imageInsets.right = titleSize.width }
-
左
title
右image
→ 居中对齐 (默认) + 间距, 参考线在中间 ━━┇━━在左
title
右image
基础上,title
左移imageTextSpacing / 2.0
,image
右移imageTextSpacing / 2.0
,buttonSize.width
增加imageTextSpacing
即可example(of: "(左 title 右 image) → 居中对齐 (默认) + 间距") { titleInsets.left -= imageTextSpacing / 2.0 titleInsets.right += imageTextSpacing / 2.0 imageInsets.left += imageTextSpacing / 2.0 imageInsets.right -= imageTextSpacing / 2.0 }
-
左
title
右image
→ 左对齐 + 间距, 参考线在左侧 ┇━━━━在左
title
右image
基础上,title
贴近左侧所以保持不变,image
右移imageTextSpacing
,buttonSize.width
增加imageTextSpacing
即可,效果图与之前相同example(of: "(左 title 右 image) → 左对齐 + 间距") { imageInsets.left += imageTextSpacing imageInsets.right -= imageTextSpacing buttonSize.width += imageTextSpacing }
-
左
title
右image
→ 右对齐 + 间距, 参考线在右侧 ━━━━┇在左
title
右image
基础上,image
贴近右侧所以保持不变,title
左移imageTextSpacing
,buttonSize.width
增加imageTextSpacing
即可,效果图与之前相同example(of: "(左 title 右 image) → 右对齐 + 间距") { titleInsets.left -= imageTextSpacing titleInsets.right += imageTextSpacing buttonSize.width += imageTextSpacing }
三、上 image
下 title
首先需要实现的是上 image
下 title
的布局,然后再添加间距。
-
上
image
下title
→ 居中对齐 (默认), 参考线在横中线 ━╋━再初始布局的基础上首先需要将
image
右移titleSize.width / 2
,title
左移imageSize.width
实现左右居中,因为是上下布局参考线为中间的横线,所以需将image
上移titleSize.height / 2
,title
下移imageSize.height / 2
实现上下居中,修改高度为titleSize.height + imageSize.height
最终达到目的。reset() example(of: "(上 image 下 title)→ 居中对齐 (默认) + 无间距") { let titleHOffset = imageSize.width / 2.0 let imageHOffset = titleSize.width / 2.0 let titleVOffset = imageSize.height / 2.0 let imageVOffset = titleSize.height / 2.0 titleInsets = UIEdgeInsets(top: titleVOffset, left: -titleHOffset, bottom: -titleVOffset, right: titleHOffset) imageInsets = UIEdgeInsets(top: -imageVOffset, left: imageHOffset, bottom: imageVOffset, right: -imageHOffset) buttonSize.height = imageSize.height + titleSize.height }
-
上
image
下title
→ 居中对齐 (默认) + 间距, 参考线在横中线 ━╋━在当前布局基础上将
image
上移mageTextSpacing / 2
,title
下移mageTextSpacing / 2
,buttonSize.height
增加imageTextSpacing
即可example(of: "(上 image 下 title) → 居中对齐 (默认) + 间距") { imageInsets.top -= imageTextSpacing / 2.0 imageInsets.bottom += imageTextSpacing / 2.0 titleInsets.top += imageTextSpacing / 2.0 titleInsets.bottom -= imageTextSpacing / 2.0 buttonSize.height += imageTextSpacing }
-
上
image
下title
→ 上对齐 + 间距, 参考线在顶部横线 ┳由于是顶部对齐所以默认
image
与title
都是贴近顶部,所以设置image
距离顶部在0,title
在当前布局基础上下移imageSize.height
实现上(image 下 title) ,然后再将title
下移imageTextSpacing
实现间距,最后 设置buttonSize.height
为imageSize.height + titleSize.height + imageTextSpacing
即可。效果图与之前相同example(of: "(上 image 下 title) → 上对齐 + 间距") { button.contentVerticalAlignment = .top imageInsets.top = 0 imageInsets.bottom = 0 titleInsets.top = imageSize.height titleInsets.bottom = -imageSize.height titleInsets.top += imageTextSpacing titleInsets.bottom -= imageTextSpacing buttonSize.height = imageSize.height + titleSize.height + imageTextSpacing }
-
上
image
下title
→ 下对齐 + 间距, 参考线在底部横线 ┻由于是底部对齐所以默认
image
与title
都是贴近底部,所以设置title
距离底部在0,image
在当前布局基础上上移titleSize.height
实现上(image 下 title) ,然后再将image
上移imageTextSpacing
实现间距,最后 设置buttonSize.height
为imageSize.height + titleSize.height + imageTextSpacing
即可, 效果图与之前相同example(of: "(上 image 下 title) → 上对齐 + 间距") { button.contentVerticalAlignment = .top titleInsets.top = 0 titleInsets.bottom = 0 imageInsets.top = -titleSize.height imageInsets.bottom = titleSize.height imageInsets.top -= imageTextSpacing imageInsets.bottom += imageTextSpacing buttonSize.height = imageSize.height + titleSize.height + imageTextSpacing }
四、上下左右的边距
到目前为止我们仅仅是在不同的布局条件下增加了 image
与 title
的间距,那么我们如果在此基础上还需要设置 上下左右的边距
该怎么处理呢,这里我们只需要调整之前一直没提到的 contentEdgeInsets
属性就可以了。这里通过设置 contentEdgeInsets
为 UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
效果如下:
对以上进行小结
我们应该始终保持
titleEdgeInsets
、imageEdgeInsets
中的left
与right
同时设置,或者是top
与bottom
同时设置,而且是一正一负,left
为+
,right
就为-
,top
为+
,bottom
就为-
,反过来亦之。应该始终以参考线为基准进行变偏移,如果是
居中对齐
那么参考线就是水平方向的中线
或者是垂直方向的中线
, 如果对齐方向是左右上下对齐
中的一个,那么参考线就是对应左右上下
的一侧。从上面的例子里可以看出,对
titleEdgeInsets
、imageEdgeInsets
的调整不会影响UIButton
的size
,所以在例子中我们需要调整其size
到合适。但是对contentEdgeInsets
的调整会影响UIButton
的size
,也正因为如此我们才可以通过contentEdgeInsets
来设置左右上下
某一侧的边距。
最后
示例代码中 UIButton
在初始化的时候 size
使用约束进行了固定,以及 UIButton
的 ImageView
及 titleLabel
的 size
也是进过测量后写死了,在真正项目应用中应该通过以下的方法来获取正确的 size
。
let textSize = previewButton.titleLabel?.sizeThatFits(CGSize.zero)
let imageSize = previewButton.imageView?.sizeThatFits(CGSize.zero)
示例代码 xcode11.2