文章迁移自简书 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
语句去除