UIButton
的布局 imageView
和 titleLabel
的過程
嗶嗶叨: 寫 iOS 代碼也有段時間了, 但始終不怎么用 system
的 UIButton
, 因為每次設(shè)置 insets
的時候都會卡住好一陣啊! 各種奇怪的偏移. 趁著有時間, 整理一下.??.
NOTE: 以下皆為偽代碼
假定條件
對于一個 UIButton
的實例 button
, 我們假定以下變量
let imageEdgeInsets = UIEdgeInsetsMake(top, left, bottom, right) // imageInsets
let titleEdgeInsets = UIEdgeInsetsMake(top, left, bottom, right) // titleEdgeInsets
let imageSize = CGSize(width, height) // image.size
let textSize = CGSize(width, height) // labelSize to fit he title text
一. 根據(jù) contentEdgeInsets
確定布局內(nèi)容大小
根據(jù) button.contentEdgeInsets
與 button.frame
計算出子控件布局范圍 contentRect
.
let contentRect = CGRect(x, y, width, height) // button.contentRect
二. 計算 imageView
與 titleLabel
的無 edgeinsets
位置
- 獲取
image.size
結(jié)合布局范圍contentRect
的大小得出imageView
的大小
// imageEdgetInsets = .zero 時, imageView 的 size
let defaultImgSize = CGSize(width = min(imageSize.width, contentRect.width),
height = min(imageSize.height, contentRect.height))
- 根據(jù)
imageView
的size
計算出在布局范圍contentRect
內(nèi)剩余的titleLabel
的布局大小以確定titleLabel
的布局大小
let remainSize = CGRect(x, y, width, height) // remainSize for titleLabel
// titleEdgeInsets = .zero 時, titleLabel 的 size
let defaultTxtSize = CGSize(width = min(textSize.width, remainSize.width),
height = textSize.height)
- 根據(jù)
button.contentHorizontalAlignment
與button.contentVerticalAlignment
決定imageView
與titleLabel
的對齊方式, 確定在imageEdgeInsets = .zero
且titleEdgeInsets = .zero
的情況下的imageView.frame
以及titleLabel.frame
.
let defaultImgRect = CGRect(x, y, width, height) // imageView.defaultRect
let defaultImgCenter = CGPoint(x, y)
let defaultTxtRect = CGRect(x, y, width, height) // imageView.defaultRect
let defaultTxtCenter = CGPoint(x, y)
這里 defaultImgRect
以及 defaultTxtRect
由 button
的 contentHorizontalAlignment
和 contentVerticalAlignment
來決定:
- 將 imageView 與 titleLabel 按照之前算好的大小左右相接,
- 將兩個控件作為整體按照上述兩個屬性, 放在 button 的左上角, 左下角, 右對齊什么的, 具體看上述屬性的值.
三. 計算加入 imageEdgeInsets
與 titleEdgeInsets
后的 result
位置
這里 edgeInsets
在這種情況下, 僅對 center
的確定有明確作用. 對 frame 的影響同時需要考慮到 intrinsicContentSize
與 contentRect
, 可以參考下述代碼與UIButton的幾個 edgeInsets 屬性:
// 計算 apply imageEdgeInsets 之后 的 imageView.size
let resultImgSize = CGSize(width = min(imageSize.width, contentRect.width - imageEdgeInsets.left - imageEdgeInsets.right),
height = min(imageSize.height, contentRect.height - imageEdgeInsets.top - imageEdgeInsets.bottom))
// 計算 apply titleEdgeInsets 之后 的 titleLabel.size
// titleLabel.height 不會被壓縮
let resultTxtSize = CGSize(width = min(textSize.width, remainSize.width - titleEdgeInsets.left - titleEdgeInsets.right),
height = textSize.height)
// 計算偏移后的 imageView 和 titleLabel 的 center
let resultImgCenter = CGPoint(x = defaultImgCenter.x + (imageEdgeInsets.left-imageEdgeInsets.right)/2,
y = defaultImgCenter.y + (imageEdgeInsets.top-imageEdgeInsets.bottom)/2)
let resultImgCenter = CGPoint(x = defaultImgCenter.x + (titleEdgeInsets.left-titleEdgeInsets.right)/2,
y = defaultImgCenter.y + (titleEdgeInsets.top-titleEdgeInsets.bottom)/2)
// last: 根據(jù) resultSize 和 resultCenter 確定最終 frame
...
以上, 就是對 UIButton
對 button.titleLabel
與 button.imageView
的布局方式的觀察結(jié)果.僅作參考. 如有不妥之處,還請 dalao 批評指正.