关于 UIButton 的 titleEdgeInsets、im
📚2019-10-20
不管是什么应用 UIButton 在项目中的使用都是必不可少的,很多时候我们会同时给 UIButton 添加上 image 和 title 以及在 image 和 title 间留一些间距, 再有时候可能还希望其左边或者是右边留有有一些间距,这样 UI 显得更加美观。可能的布局看起来像这样:
UIButton默认样式
image 与 title 有间距
image 与 title 有间距 + 左侧间距
image 与 title上下布局 + 中间间距 + 四周边距
尽管这看起来很容易实现,只要合理的设置 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右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基础上,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下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与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) 效果如下:
image 与 title 间距 + 四周边距
对以上进行小结
-
我们应该始终保持
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