// // UIButton+Extension.swift // QuickSearchLocation // // Created by mac on 2024/4/11. // import UIKit extension UIButton { enum ThemeButtonType { case mainTheme } // MARK: 1.1、创建一个带颜色的 Button, 默认为主题色,默认高度44 /// 创建一个带颜色的 Button /// - Parameters: /// - type: 类型 /// - height: 高度 /// - Returns: 返回自身 @discardableResult static func normal() -> UIButton { let normalColor: UIColor let disabledColor: UIColor let titleColorNormal: UIColor let titleColorDisable: UIColor normalColor = QSLColor.themeMainColor disabledColor = QSLColor.buttonDisabledColor titleColorNormal = .white titleColorDisable = .white let btn = UIButton(type: .custom).font(.systemFont(ofSize: 16)) btn.setTitleColor(titleColorNormal, for: .normal) btn.setTitleColor(titleColorDisable, for: .disabled) btn.setBackgroundColor(normalColor, forState: .normal) btn.setBackgroundColor(disabledColor, forState: .disabled) return btn } //MARK: 1.3、设置背景色 /// 设置背景色 /// - Parameters: /// - color: 背景色 /// - forState: 状态 func setBackgroundColor(_ color: UIColor, forState: UIControl.State) { self.setBackgroundImage(backgroundImage(color), for: forState) } private func backgroundImage(_ color: UIColor) -> UIImage? { UIGraphicsBeginImageContext(CGSize(width: 1, height: 1)) UIGraphicsGetCurrentContext()?.setFillColor(color.cgColor) UIGraphicsGetCurrentContext()?.fill(CGRect(x: 0, y: 0, width: 1, height: 1)) let colorImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return colorImage } } // MARK: - 二、链式调用 public extension UIButton { // MARK: 2.1、设置title /// 设置title /// - Parameters: /// - text: 文字 /// - state: 状态 /// - Returns: 返回自身 @discardableResult func title(_ text: String, _ state: UIControl.State = .normal) -> Self { setTitle(text, for: state) return self } // MARK: 2.2、设置文字颜色 /// 设置文字颜色 /// - Parameters: /// - color: 文字颜色 /// - state: 状态 /// - Returns: 返回自身 @discardableResult func textColor(_ color: UIColor, _ state: UIControl.State = .normal) -> Self { setTitleColor(color, for: state) return self } // MARK: 2.3、设置字体大小(UIFont) /// 设置字体大小 /// - Parameter font: 字体 UIFont /// - Returns: 返回自身 @discardableResult func font(_ font: UIFont) -> Self { titleLabel?.font = font return self } // MARK: 2.4、设置字体大小(CGFloat) /// 设置字体大小(CGFloat) /// - Parameter fontSize: 字体的大小 /// - Returns: 返回自身 @discardableResult func font(_ fontSize: CGFloat) -> Self { titleLabel?.font = UIFont.textF(fontSize) return self } // MARK: 2.5、设置字体中等粗(CGFloat) /// 设置字体大小(CGFloat) /// - Parameter fontSize: 字体的大小 /// - Returns: 返回自身 @discardableResult func mediumFont(_ fontSize: CGFloat) -> Self { titleLabel?.font = UIFont.textM(fontSize) return self } // MARK: 2.6、设置字体粗体 /// 设置粗体 /// - Parameter fontSize: 设置字体粗体 /// - Returns: 返回自身 @discardableResult func boldFont(_ fontSize: CGFloat) -> Self { titleLabel?.font = UIFont.textB(fontSize) return self } // MARK: 2.7、设置图片 /// 设置图片 /// - Parameters: /// - image: 图片 /// - state: 状态 /// - Returns: 返回自身 @discardableResult func image(_ image: UIImage?, _ state: UIControl.State = .normal) -> Self { setImage(image, for: state) return self } } // MARK: - UIButton 图片 与 title 位置关系 extension UIButton { /// 图片 和 title 的布局样式 enum ImageTitleLayout { case imgTop case imgBottom case imgLeft case imgRight } // MARK: 3.1、设置图片和 title 的位置关系(提示:title和image要在设置布局关系之前设置) /// 设置图片和 title 的位置关系(提示:title和image要在设置布局关系之前设置) /// - Parameters: /// - layout: 布局 /// - spacing: 间距 /// - Returns: 返回自身 @discardableResult func setImageTitleLayout(_ layout: ImageTitleLayout, spacing: CGFloat = 0) -> UIButton { switch layout { case .imgLeft: alignHorizontal(spacing: spacing, imageFirst: true) case .imgRight: alignHorizontal(spacing: spacing, imageFirst: false) case .imgTop: alignVertical(spacing: spacing, imageTop: true) case .imgBottom: alignVertical(spacing: spacing, imageTop: false) } return self } /// 水平方向 /// - Parameters: /// - spacing: 间距 /// - imageFirst: 图片是否优先 private func alignHorizontal(spacing: CGFloat, imageFirst: Bool) { let edgeOffset = spacing / 2 imageEdgeInsets = UIEdgeInsets(top: 0, left: -edgeOffset, bottom: 0,right: edgeOffset) titleEdgeInsets = UIEdgeInsets(top: 0, left: edgeOffset, bottom: 0, right: -edgeOffset) if !imageFirst { transform = CGAffineTransform(scaleX: -1, y: 1) imageView?.transform = CGAffineTransform(scaleX: -1, y: 1) titleLabel?.transform = CGAffineTransform(scaleX: -1, y: 1) } contentEdgeInsets = UIEdgeInsets(top: 0, left: edgeOffset, bottom: 0, right: edgeOffset) } /// 垂直方向 /// - Parameters: /// - spacing: 间距 /// - imageTop: 图片是不是在顶部 private func alignVertical(spacing: CGFloat, imageTop: Bool) { guard let imageWidth = self.imageView?.qsl_width, let imageHeight = self.imageView?.qsl_height, let text = self.titleLabel?.text, let font = self.titleLabel?.font else { return } let labelString = NSString(string: text) let titleSize = labelString.size(withAttributes: [NSAttributedString.Key.font: font]) let titleHeight = titleSize.height let titleWidth = titleSize.width let insetAmount = spacing / 2 if imageTop { imageEdgeInsets = UIEdgeInsets(top: -titleHeight - insetAmount, left: (self.qsl_width - imageWidth) / 2, bottom: 0, right: (self.qsl_width - imageWidth) / 2 - titleWidth) titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageWidth, bottom: -imageWidth - insetAmount, right: 0) } else { imageEdgeInsets = UIEdgeInsets(top: 0, left: (self.qsl_width - imageWidth) / 2, bottom: -titleHeight - insetAmount, right: (self.qsl_width - imageWidth) / 2 - titleWidth) titleEdgeInsets = UIEdgeInsets(top: -imageHeight - insetAmount, left: -imageWidth, bottom: 0, right: 0) } } } extension UIButton { //倒计时 func countDown(_ timeOut: Int){ //倒计时时间 var timeout = timeOut let queue:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default) let _timer:DispatchSource = DispatchSource.makeTimerSource(flags: [], queue: queue) as! DispatchSource _timer.schedule(wallDeadline: DispatchWallTime.now(), repeating: .seconds(1)) //每秒执行 _timer.setEventHandler(handler: { () -> Void in if(timeout<=0){ //倒计时结束,关闭 _timer.cancel(); DispatchQueue.main.sync(execute: { () -> Void in self.setTitle("重新发送", for: .normal) self.isEnabled = true }) }else{//正在倒计时 let seconds = timeout DispatchQueue.main.sync(execute: { () -> Void in let str = String(describing: seconds) self.setTitle("\(str)s", for: .normal) self.isEnabled = false }) timeout -= 1; } }) _timer.resume() } } // MARK: - 六、Button扩大点击事件 private var UIButtonExpandSizeKey = UnsafeRawPointer("UIButtonExpandSizeKey".withCString { $0 }) public extension UIButton { override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { if self.touchExtendInset == .zero || isHidden || !isEnabled { return super.point(inside: point, with: event) } var hitFrame = bounds.inset(by: self.touchExtendInset) hitFrame.size.width = max(hitFrame.size.width, 0) hitFrame.size.height = max(hitFrame.size.height, 0) return hitFrame.contains(point) } } public extension UIButton { // MARK: 6.1、扩大UIButton的点击区域,向四周扩展10像素的点击范围 /// 扩大按钮点击区域 如UIEdgeInsets(top: -50, left: -50, bottom: -50, right: -50)将点击区域上下左右各扩充50 /// /// 提示:theView 扩展点击相应区域时,其扩展的区域不能超过 superView 的 frame ,否则不会相应改点击事件;如果需要响应点击事件,需要对其 superView 进行和 theView 进行同样的处理 var touchExtendInset: UIEdgeInsets { get { if let value = objc_getAssociatedObject(self, &UIButtonExpandSizeKey) { var edgeInsets: UIEdgeInsets = UIEdgeInsets.zero (value as AnyObject).getValue(&edgeInsets) return edgeInsets } else { return UIEdgeInsets.zero } } set { objc_setAssociatedObject(self, &UIButtonExpandSizeKey, NSValue(uiEdgeInsets: newValue), .OBJC_ASSOCIATION_COPY_NONATOMIC) } } }