直接上代碼,看注釋
let btn = UIButton()
btn.translatesAutoresizingMaskIntoConstraints = false
btn.addTarget(self, action: #selector(filterConditionSelectAction(btn:)), for: .touchUpInside)
if #available(iOS 15.0, *) {
// 初始化一個(gè)configuration姜胖,有多種方法誉帅,可根據(jù)需要選擇
btn.configuration = UIButton.Configuration.plain()
// title 和 subtitle的對(duì)其關(guān)系,文本是上下排版的
btn.configuration?.titleAlignment = .leading
// title he subtitle的間距
btn.configuration?.titlePadding = 16.scaleToScreen()
// image 和 文本 的相對(duì)位置
btn.configuration?.imagePlacement = .trailing
// image 和 文本的間距
btn.configuration?.imagePadding = 16.scaleToScreen()
// button的內(nèi)容(title谭期,subtitle堵第,image)顯示后與按鈕的邊距,默認(rèn)由一段距離
btn.configuration?.contentInsets = NSDirectionalEdgeInsets.zero
// 設(shè)置按鈕的狀態(tài)變化的監(jiān)聽(tīng)隧出,根據(jù)變化來(lái)改變按鈕的顯示內(nèi)容,之前都是全部設(shè)置進(jìn)去自動(dòng)切換的阀捅,現(xiàn)在不行了
btn.configurationUpdateHandler = {(button: UIButton) -> Void in
//根據(jù)狀態(tài)修改內(nèi)容
switch button.state {
case .normal, .highlighted:
// image變化
button.configuration?.image = UIImage.arrowPickUp
// 背景的變化胀瞪,默認(rèn)會(huì)有些自帶效果,
button.configuration?.background.backgroundColor = .clear
// 字體的樣式與之前一樣
button.configuration?.attributedTitle = AttributedString(title, attributes: AttributeContainer([
NSAttributedString.Key.font : UIFont.customMediumFont(ofSize: UIFont.sizeL),
NSAttributedString.Key.foregroundColor : UIColor.whiteAlpha50 ?? .red]))
// 子標(biāo)題饲鄙,iOS15之后才有凄诞,對(duì)應(yīng)的button.subtitleLabel
button.configuration?.subtitle = "abc"
case .selected, [.selected, .highlighted]:
// image變化,與上面對(duì)應(yīng)
button.configuration?.image = UIImage.arrowUnfold
case .disabled:
Log.Debug(message: "不可\(btn.state)")
default:
Log.Debug(message: "默認(rèn)值\(btn.state)")
}
button.updateConfiguration()
}
} else {
// iOS15 之前的屬性設(shè)置
btn.setTitle(title, for: .normal)
// 字體顏色
btn.setTitleColor(UIColor.whiteAlpha50, for: .normal)
btn.setTitleColor(UIColor.whiteAlpha50, for: .selected)
// 設(shè)置圖片各種狀態(tài)都需要設(shè)置
btn.setImage(UIImage.arrowUnfold, for: .normal)
btn.setImage(UIImage.arrowUnfold, for: .highlighted)
btn.setImage(UIImage.arrowPickUp, for: .selected)
btn.setImage(UIImage.arrowPickUp, for: [.selected, .highlighted])
btn.titleLabel?.font = UIFont.customFont(ofSize: UIFont.sizeL)
// 改變title與image的位置關(guān)系
btn.titleEdgeInsets = UIEdgeInsets(top: 0, left: -15.scaleToScreen(), bottom: 0, right: 15.scaleToScreen())
btn.imageEdgeInsets = UIEdgeInsets(top: 0, left: 51.scaleToScreen(), bottom: 0, right: -51.scaleToScreen())
btn.backgroundColor = .gray
}
view.addSubview(btn)
按鈕的內(nèi)部布局控制比之前簡(jiǎn)單很多忍级,不像之前帆谍,簡(jiǎn)單的 可以通過(guò)titleEdgeInsets 和 imageEdgeInsets來(lái)處理,復(fù)雜的就需要自定了轴咱,
自定義demo
import UIKit
public enum CustomButtonLayoutType : Int {
case system
case imageTop
case imageRight
case avatar
}
public class CustomButton: UIButton {
public var cusFont: UIFont? {
get {
return self.titleLabel?.font
}
set {
self.titleLabel?.font = newValue
}
}
public var layoutType: CustomButtonLayoutType = .system
override public func titleRect(forContentRect contentRect: CGRect) -> CGRect {
if layoutType == .system || contentRect == CGRect.zero {
return super.titleRect(forContentRect: contentRect)
}
let imageSize = super.imageRect(forContentRect: contentRect)
let titleSize = calculateTitleSize(size: contentRect.size)
switch layoutType {
case .imageTop:
let x = (contentRect.width - titleSize.width) / 2 + contentRect.minX + self.titleEdgeInsets.left
let y = (contentRect.height + imageSize.height - titleSize.height) / 2 + contentRect.minY + self.titleEdgeInsets.top
return CGRect(x: x, y: y, width: titleSize.width, height: titleSize.height)
case .imageRight:
let x = (contentRect.width - imageSize.width - titleSize.width) / 2 + contentRect.minX + self.titleEdgeInsets.left
let y = (contentRect.height - titleSize.height) / 2 + contentRect.minY + self.titleEdgeInsets.top
return CGRect(x: x, y: y, width: titleSize.width, height: titleSize.height)
default:
return super.titleRect(forContentRect: contentRect)
}
}
override public func imageRect(forContentRect contentRect: CGRect) -> CGRect {
if layoutType == .system || contentRect == CGRect.zero{
return super.imageRect(forContentRect: contentRect)
}
let imageSize = super.imageRect(forContentRect: contentRect)
let titleSize = calculateTitleSize(size: contentRect.size)
switch layoutType {
case .imageTop:
let x = (contentRect.width - imageSize.width) / 2 + contentRect.minX + self.imageEdgeInsets.left
let y = (contentRect.height - imageSize.height - titleSize.height) / 2 + contentRect.minY + self.imageEdgeInsets.top
return CGRect(x: x, y: y, width: imageSize.width, height: imageSize.height)
case .imageRight:
let x = (contentRect.width + titleSize.width - imageSize.width) / 2 + contentRect.minX + self.imageEdgeInsets.left
let y = (contentRect.height - imageSize.height) / 2 + contentRect.minY + self.imageEdgeInsets.top
return CGRect(x: x, y: y, width: imageSize.width, height: imageSize.height)
case .avatar:
let bgImageWidth: CGFloat = self.currentBackgroundImage?.size.width ?? imageSize.width
let width: CGFloat = imageSize.width * contentRect.width / bgImageWidth
let height = width * imageSize.height / imageSize.width
let x = (contentRect.width - width) + contentRect.minX + self.imageEdgeInsets.left
let y = (contentRect.height - height) + contentRect.minY + self.imageEdgeInsets.top
return CGRect(x: x, y: y, width: width, height: height)
default:
return super.imageRect(forContentRect: contentRect)
}
}
override public func backgroundRect(forBounds bounds: CGRect) -> CGRect {
return super.backgroundRect(forBounds: bounds)
}
private func calculateTitleSize(size: CGSize) -> CGSize {
if let title = self.currentAttributedTitle {
return title.size()
}
if let title = self.currentTitle {
let options: NSStringDrawingOptions = .usesLineFragmentOrigin
let attributes : [NSAttributedString.Key : Any] = [.font: cusFont ?? UIFont.customFont(ofSize: UIFont.size1xl)]
return title.boundingRect(with: size, options: options, attributes: attributes, context: nil).size
}
return CGSize.zero
}
}