关于 UIButton 的 titleEdgeInsets、imageEdgeInsets 及 contentEdgeInsets

📚2019-10-20

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

UIButton默认样式

image 与 title 有间距

image 与 title 有间距 + 左侧间距

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
    }
    
(左 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
    }
    
上 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
    }
    
(上 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) 效果如下:

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • @class UIImage, UIFont, UIColor, UIImageView, UILabel; ty...
    彬至睢阳阅读 1,584评论 0 1
  • 各种纯css图标 CSS3可以实现很多漂亮的图形,我收集了32种图形,在下面列出。直接用CSS3画出这些图形,要比...
    剑残阅读 9,176评论 0 8
  • 学习CSS的最佳网站没有之一 http://www.w3school.com.cn/tags/index.asp ...
    Amyyy_阅读 919评论 0 1
  • 一、CSS入门 1、css选择器 选择器的作用是“用于确定(选定)要进行样式设定的标签(元素)”。 有若干种形式的...
    宠辱不惊丶岁月静好阅读 1,540评论 0 6
  • 供需定理:8月25日 成本决定价格?你太天真了 经济学告诉我们,产品有价,不是因为制造产品有成本,而是因为市场对产...
    一一休阅读 695评论 0 0