文章遷移自簡書 2016.09.04 14:35:01 著swift
UIButton
的相關屬性UIButton
提供的設置title
和image
的方法,默認是圖片在左文字在右的樣式.以下圖:bash
而咱們在開發過程當中經常要調整爲文字在左圖片在右,或者文字在上圖片在下等樣式.ide
系統同時提供了設置圖片和文字位置的edgeInsets
的屬性ui
@property(nonatomic) UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR; // default is UIEdgeInsetsZero
@property(nonatomic) UIEdgeInsets titleEdgeInsets; // default is UIEdgeInsetsZero
@property(nonatomic) UIEdgeInsets imageEdgeInsets; // default is UIEdgeInsetsZero
複製代碼
提示:UI_APPEARANCE_SELECTOR
標記的屬性都支持經過外觀代理來定製。atom
這樣就咱們就能夠經過設置 titleEdgeInsets
和 imageEdgeInsets
來調整圖片和文字的相對位置了;spa
UIEdgeInsets
的解釋類型代理
typedef struct UIEdgeInsets {
CGFloat top, left, bottom, right; // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'
} UIEdgeInsets;
複製代碼
設置各個值得含義code
//UIEdgeInsetsMake(<#T##top: CGFloat##CGFloat#>, <#T##left: CGFloat##CGFloat#>, <#T##bottom: CGFloat##CGFloat#>, <#T##right: CGFloat##CGFloat#>)
testBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 10, 40, 10);
//0 表示據原來的頂部 爲0
//10 表示左邊框右移 10 (同理 -10 表示左邊框左移 10)
//40 表示下邊框上移 40
//10 表示右邊框左移 10 (同理 -10 表示右邊框右移 10)
複製代碼
總之:這些參數 正值都是表示 向相反的方向移動相應的距離(例如:對 top
正值表示向下移動,負值表示向上移動) 這樣咱們就能夠在 UIButton
的外部輕鬆設置想要的樣式orm
咱們如今把相關的設置抽出來作成一個 extension
的方法(一下以文字在左圖片在右進行設置)cdn
1.新建一個 swift
文件命名爲 Button_Extension
, 添加代碼以下;
import UIKit
extension UIButton {
/// 設置文字在左圖片在右,圖文間距默認爲`0.0`
func setupImageAtRight(space: CGFloat = 0.0) {
/*1*/
DRPrint("獲取imageWidth")
guard let imageWidth = imageView?.frame.size.width else {
DRPrint("noImage")
return
}
/*2*/
DRPrint("獲取titleWidth")
guard let titleWidth = titleLabel?.frame.size.width else {
DRPrint("noTitle")
return
}
//(備註:`button`不做爲`navigationItem.titleView`是默認`titleLabel`和`imageView`距離邊界是有一個空隙的)
titleEdgeInsets = UIEdgeInsetsMake(0.0, -(imageWidth + space * 0.5), 0, imageWidth + space * 0.5)
imageEdgeInsets = UIEdgeInsetsMake(0.0, titleWidth + space * 0.5, 0.0, -(space * 0.5 + titleWidth))
//打開註釋就能看到普通的`button`默認`titleLabel`和`imageView`距離邊界爲`0`
//backgroundColor = UIColor.greenColor()
}
}
複製代碼
上述代碼爲所有操做, 可是在第一次封裝中把 /*2*/
寫在了 /*1*/
的前面, 始終得不到正確的效果.
此處存疑: 爲何先獲取
titleWidth
則titleWidth
值始終未0.0
(能獲取到titleLabel.text
和titleLabel.font
,字符串計算width
能正確得到),可是當先獲取imageWidth
時,則能獲取到正確的titleWidth
?
通過研究發現:
經過自定義一個
DRButton
並重寫-layoutSubviews
方法發現, 調用imageView?.frame
時會先調用-layoutSubviews
,才能獲取到imageWidth
,而titleLabel?.frame
不會調用-layoutSubviews
,所以先獲取titleWidth
不會獲得正確的值只會獲得0.0
.
你也能夠本身寫一下
import UIKit
class TestBtn: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
DRPrint("button.layoutSubiews")
}
}
複製代碼
試試打印的結果
先獲取 imageWidth
的打印結果
Button_extension.swift-setupImageAtRight-14:獲取imageWidth
TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
Button_extension.swift-setupImageAtRight-19:獲取titleWidth
TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
複製代碼
先獲取titleWidth
的打印結果
Button_extension.swift-setupImageAtRight-14:獲取titleWidth
Button_extension.swift-setupImageAtRight-19:獲取imageWidth
TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
複製代碼
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
addButton()
//addButton("testTitle")
//addButton("testLongLongTitle")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
// MARK:- 設置UI
extension ViewController {
func addButton(title: String = "78987fded") {
view.backgroundColor = UIColor.lightGrayColor()
let button = TestBtn()
button.setTitle(title, forState: .Normal)
button.setImage(UIImage(named: "navigationbar_arrow_down"), forState: .Normal)
button.setImage(UIImage(named: "navigationbar_arrow_up"), forState: .Selected)
//button.setTitleColor(UIColor.grayColor(), forState: .Normal)
button.titleLabel?.font = UIFont.systemFontOfSize(14);
button.sizeToFit()
button.center = view.center
//設置圖片和標題的位置
button.setupImageAtRight()
button.backgroundColor = UIColor.greenColor()
view.addSubview(button)
}
}
複製代碼
效果圖:
/// 設置圖片在右,圖文間隔默認爲`0.0`
func setupImageAtRight(space: CGFloat = 0.0) {
//第一種方法:經過計算字符串長度來調整
/* let titleString = currentTitle! as NSString let size = CGSizeMake(CGFloat(MAXFLOAT), bounds.size.height) let atttibutes = [NSFontAttributeName:titleLabel!.font] let titleWidth = titleString.boundingRectWithSize(size, options: .UsesLineFragmentOrigin, attributes: atttibutes, context: nil).size.width */
/* 此處存疑: 爲何先獲取`titleWidth`則`titleWidth`值始終未`0.0`(能獲取到`titleLabel.text`和`titleLabel.font`,字符串計算`width`能正確得到),可是當先獲取`imageWidth`時,則能獲取到正確的`titleWidth`🐷 疑惑解答: 經過自定義一個`DRButton`並重寫`-layoutSubviews`方法發現,調用`imageView?.frame`時會先調用`-layoutSubviews`,才能獲取到`imageWidth`,而`titleLabel?.frame`不會調用`-layoutSubviews`,所以先獲取`titleWidth`不會獲得正確的值只會獲得`0.0` */
//經過獲取`titleLabel`的`width`來調整
guard let imageWidth = imageView?.frame.size.width else {
return
}
guard let titleWidth = titleLabel?.frame.size.width else {
return
}
/* DRPrint("titleWidth = \(titleWidth)") DRPrint("bounds.size = \(bounds.size)") DRPrint("調整前_ titleLabel.frame = \(titleLabel!.frame)") DRPrint("調整前_ imageView.frame = \(imageView!.frame)") DRPrint(titleLabel?.frame.size.width) */
/* testBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 10, 40, 10); 0 表示據原來的頂部 爲0 10 表示左邊框右移 10 (同理 -10 表示左邊框左移 10) 40 表示下邊框上移 40 10 表示右邊框左移 10 (同理 -10 表示右邊框右移 10) 備註 這些參數 正值都是表示 向相反的方向移動相應的距離 */
titleEdgeInsets = UIEdgeInsetsMake(0.0, -(imageWidth + space * 0.5), 0, imageWidth + space * 0.5)
imageEdgeInsets = UIEdgeInsetsMake(0.0, titleWidth + space * 0.5, 0.0, -(space * 0.5 + titleWidth))
}
複製代碼
// MARK:- 簡單打印
func DRPrint<T>(message: T,file: NSString = #file,lineNum: Int = #line,funcName:String = #function) -> Void {
#if DEBUG
let fileName = (file as NSString).lastPathComponent
print("\(fileName)-\(funcName)-\(lineNum):\(message)")
#endif
}
複製代碼
不出打印信息的請把 #if
語句去除