关于 UIButton 的 titleEdgeInsets、imageEdgeInsets 及 contentEdgeInsets

2019-10-20

不管是什么应用 UIButton 在项目中的使用都是必不可少的,很多时候我们会同时给 UIButton 添加上 imagetitle 以及在 imagetitle 间留一些间距, 再有时候可能还希望其左边或者是右边留有有一些间距,这样 UI 显得更加美观。可能的布局看起来像这样:

UIButton默认样式

image 与 title 有间距

image 与 title 有间距 + 左侧间距

关于 UIButton 的 titleEdgeInsets、imageEdgeInsets 及 contentEdgeInsets_第1张图片
image 与 title上下布局 + 中间间距 + 四周边距

尽管这看起来很容易实现,只要合理的设置 UIButtontitleEdgeInsetsimageEdgeInsetscontentEdgeInsets 等属性就可以实现这些效果,但是不得不说还是有很多开发者不确定如何控制这几个属性,而导致项目相关的地方出现了一些问题,所以接下来增对个人的理解对这几个属性的设置进行一些说明。

UIButton 中 imageView 与 titleLabel 的布局

UIButton 的内部布局中假设有个参考线imageViewtitleLabel 的布局均以该参考线为参照左右上下进行偏移,最终实现在 imagetitle 间添加间距 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)
}


一、 左 imagetitle 的布局

  1. imagetitle → 居中对齐 (默认), 参考线为中线 ━━┇━━

    布局实现:在当前布局上以中线为参考线那么需将 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
    }      
    


  1. imagetitle → 左对齐, 参考线在左侧 ┇━━━━

    在当前布局上 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
    }
    
    


  1. imagetitle → 右对齐, 参考线在右侧 ┇━━━━

    在当前布局上 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
    }    
    


二、 左 titleimage 的布局

首先需要实现的是左边 title 右边 image的布局, 然后再添加间距

  1. titleimage → 居中对齐 (默认) + 无间距

    在初始布局上将 title 左移 imageSize.widthimage 右移 titleSize.width 即可达到效果

    example(of: "左 title 右 image → 居中对齐 (默认) + 无间距") {
        titleInsets.left = -imageSize.width
        titleInsets.right = imageSize.width
        imageInsets.left = titleSize.width
        imageInsets.right = titleSize.width
    }
    
左 title 右 image → 居中对齐 (默认) + 无间距


  1. titleimage → 居中对齐 (默认) + 间距, 参考线在中间 ━━┇━━

    在左 titleimage 基础上,title 左移 imageTextSpacing / 2.0, image 右移 imageTextSpacing / 2.0buttonSize.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
    }
    
关于 UIButton 的 titleEdgeInsets、imageEdgeInsets 及 contentEdgeInsets_第2张图片
(左 title 右 image) → 居中对齐 (默认) + 间距


  1. titleimage → 左对齐 + 间距, 参考线在左侧 ┇━━━━

    在左 titleimage 基础上,title 贴近左侧所以保持不变, image 右移 imageTextSpacingbuttonSize.width 增加 imageTextSpacing 即可,效果图与之前相同

    example(of: "(左 title 右 image) → 左对齐 + 间距") {
        imageInsets.left += imageTextSpacing
        imageInsets.right -= imageTextSpacing
    
        buttonSize.width += imageTextSpacing
    }
    


  1. titleimage → 右对齐 + 间距, 参考线在右侧 ━━━━┇

    在左 titleimage 基础上,image 贴近右侧所以保持不变, title 左移 imageTextSpacingbuttonSize.width 增加 imageTextSpacing 即可,效果图与之前相同

    example(of: "(左 title 右 image) → 右对齐 + 间距") {
        titleInsets.left -= imageTextSpacing
        titleInsets.right += imageTextSpacing
    
        buttonSize.width += imageTextSpacing
    }
    


三、上 imagetitle

首先需要实现的是上 imagetitle 的布局,然后再添加间距。

  1. imagetitle → 居中对齐 (默认), 参考线在横中线 ━╋━

    再初始布局的基础上首先需要将 image 右移 titleSize.width / 2title 左移 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
    }
    
关于 UIButton 的 titleEdgeInsets、imageEdgeInsets 及 contentEdgeInsets_第3张图片
上 image 下 title
  1. imagetitle → 居中对齐 (默认) + 间距, 参考线在横中线 ━╋━

    在当前布局基础上将 image 上移 mageTextSpacing / 2title 下移 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
    }
    
关于 UIButton 的 titleEdgeInsets、imageEdgeInsets 及 contentEdgeInsets_第4张图片
(上 image 下 title) → 居中对齐 (默认) + 间距
  1. imagetitle → 上对齐 + 间距, 参考线在顶部横线 ┳

    由于是顶部对齐所以默认 imagetitle 都是贴近顶部,所以设置 image 距离顶部在0, title 在当前布局基础上下移 imageSize.height 实现上(image 下 title) ,然后再将 title 下移 imageTextSpacing 实现间距,最后 设置 buttonSize.heightimageSize.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
    }
    
  2. imagetitle → 下对齐 + 间距, 参考线在底部横线 ┻

    由于是底部对齐所以默认 imagetitle 都是贴近底部,所以设置 title 距离底部在0, image 在当前布局基础上上移 titleSize.height 实现上(image 下 title) ,然后再将 image 上移 imageTextSpacing 实现间距,最后 设置 buttonSize.heightimageSize.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
    }
    


四、上下左右的边距

到目前为止我们仅仅是在不同的布局条件下增加了 imagetitle 的间距,那么我们如果在此基础上还需要设置 上下左右的边距 该怎么处理呢,这里我们只需要调整之前一直没提到的 contentEdgeInsets 属性就可以了。这里通过设置 contentEdgeInsetsUIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) 效果如下:

关于 UIButton 的 titleEdgeInsets、imageEdgeInsets 及 contentEdgeInsets_第5张图片
image 与 title 间距 + 四周边距

对以上进行小结

  • 我们应该始终保持 titleEdgeInsetsimageEdgeInsets 中的 leftright 同时设置,或者是 topbottom 同时设置,而且是一正一负,left+, right 就为 -top+, bottom 就为 -,反过来亦之。

  • 应该始终以参考线为基准进行变偏移,如果是 居中对齐 那么参考线就是 水平方向的中线 或者是 垂直方向的中线, 如果对齐方向是 左右上下对齐 中的一个,那么参考线就是对应 左右上下 的一侧。

  • 从上面的例子里可以看出,对 titleEdgeInsetsimageEdgeInsets 的调整不会影响 UIButtonsize,所以在例子中我们需要调整其 size 到合适。但是对 contentEdgeInsets 的调整会影响 UIButtonsize,也正因为如此我们才可以通过 contentEdgeInsets 来设置 左右上下 某一侧的边距。

最后

示例代码中 UIButton 在初始化的时候 size 使用约束进行了固定,以及 UIButtonImageViewtitleLabelsize 也是进过测量后写死了,在真正项目应用中应该通过以下的方法来获取正确的 size

    let textSize = previewButton.titleLabel?.sizeThatFits(CGSize.zero)
    let imageSize = previewButton.imageView?.sizeThatFits(CGSize.zero)


示例代码 xcode11.2

你可能感兴趣的:(关于 UIButton 的 titleEdgeInsets、imageEdgeInsets 及 contentEdgeInsets)