swift常用扩展(UIButton)

1,915 阅读2分钟

UIButton 各种点击事件封装,事件响应区域修改,文字图片位置(垂直居中,水平居中)

import Foundation
import UIKit

// MARK: - 点击事件闭包与扩充点击范围
typealias BtnAction = (UIButton)->()
extension UIButton{
    private struct AssociatedKeys{
        static var actionKey = "actionKey"
    }
    
    @objc dynamic var action: BtnAction? {
        set{
            objc_setAssociatedObject(self,&AssociatedKeys.actionKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY)
        }
        get{
            if let action = objc_getAssociatedObject(self, &AssociatedKeys.actionKey) as? BtnAction{
                return action
            }
            return nil
        }
    }
    
    /// 添加一个点击事件
    /// - Parameter action: 点击时执行的闭包
    @discardableResult // 消除未使用返回值时的警告
    func addClickAction(action:@escaping BtnAction) -> UIButton {
        return self.addEvent(event: .touchUpInside, action: action)
    }
    
    
    /// 添加一个事件
    /// - Parameters:
    ///   - event: 添加的事件
    ///   - action: 事件响应时执行的闭包
    @discardableResult //消除未使用返回值时的警告
    func addEvent(event:UIControl.Event, action:@escaping  BtnAction ) -> UIButton{
        self.action = action
        self.addTarget(self, action: #selector(touchUpInSideBtnAction), for: event)
        return self
    }

    @objc func touchUpInSideBtnAction(btn: UIButton) {
         if let action = self.action {
             action(btn)
         }
    }
    
    
    @discardableResult //消除未使用返回值时的警告
    func addCountdown(time:Int, endAction:@escaping ()->()) -> UIButton {
        //倒计时时间
        var timeout = time
        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.isEnabled = true
                    endAction()
                })
            }else{//正在倒计时
                let seconds = timeout
                DispatchQueue.main.sync(execute: { () -> Void in
                    let str = String(describing: seconds)
                    let s = "秒"
                    self.titleLabel?.text = "\(str)\(s)"
                    self.setTitle("\(str)\(s)", for: .normal)
                    self.isEnabled = false
                })
                timeout -= 1;
            }
        })
        _timer.resume()
        return self
    }
    
    
    // 改进写法【推荐】
    private struct RuntimeKey {
        static let clickEdgeInsets = UnsafeRawPointer.init(bitPattern: "clickEdgeInsets".hashValue)
        /// ...其他Key声明
    }
    /// 需要扩充的点击边距
    public var addClickEdgeInsets: UIEdgeInsets? {
        set {
            objc_setAssociatedObject(self, UIButton.RuntimeKey.clickEdgeInsets!, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY)
        }
        get {
            return objc_getAssociatedObject(self, UIButton.RuntimeKey.clickEdgeInsets!) as? UIEdgeInsets ?? UIEdgeInsets.zero
        }
    }
    // 重写系统方法修改点击区域
    open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        super.point(inside: point, with: event)
        var bounds = self.bounds
        if (addClickEdgeInsets != nil) {
            let x: CGFloat = -(addClickEdgeInsets?.left ?? 0)
            let y: CGFloat = -(addClickEdgeInsets?.top ?? 0)
            let width: CGFloat = bounds.width + (addClickEdgeInsets?.left ?? 0) + (addClickEdgeInsets?.right ?? 0)
            let height: CGFloat = bounds.height + (addClickEdgeInsets?.top ?? 0) + (addClickEdgeInsets?.bottom ?? 0)
            bounds = CGRect(x: x, y: y, width: width, height: height) //负值是方法响应范围
        }
        return bounds.contains(point)
    }
    
    
}


// MARK: - 图片文字位置
extension UIButton{
    
    enum RGButtonImagePosition {
        case top          //图片在上,文字在下,垂直居中对齐
        case bottom       //图片在下,文字在上,垂直居中对齐
        case left         //图片在左,文字在右,水平居中对齐
        case right        //图片在右,文字在左,水平居中对齐
    }
    
    
    /// - Description 设置Button图片的位置
    /// - Parameters:
    ///   - style: 图片位置
    ///   - spacing: 按钮图片与文字之间的间隔
    func imagePosition(style: RGButtonImagePosition, spacing: CGFloat) {
        //得到imageView和titleLabel的宽高
        let imageWidth = self.imageView?.frame.size.width
        let imageHeight = self.imageView?.frame.size.height
        var labelWidth: CGFloat! = 0.0
        var labelHeight: CGFloat! = 0.0
        labelWidth = self.titleLabel?.intrinsicContentSize.width
        labelHeight = self.titleLabel?.intrinsicContentSize.height
        //初始化imageEdgeInsets和labelEdgeInsets
        var imageEdgeInsets = UIEdgeInsets.zero
        var labelEdgeInsets = UIEdgeInsets.zero
        //根据style和space得到imageEdgeInsets和labelEdgeInsets的值
        switch style {
        case .top:
            //上 左 下 右
            imageEdgeInsets = UIEdgeInsets(top: -labelHeight-spacing/2, left: 0, bottom: 0, right: -labelWidth)
            labelEdgeInsets = UIEdgeInsets(top: 0, left: -imageWidth!, bottom: -imageHeight!-spacing/2, right: 0)
            break;
        case .left:
            imageEdgeInsets = UIEdgeInsets(top: 0, left: -spacing/2, bottom: 0, right: spacing)
            labelEdgeInsets = UIEdgeInsets(top: 0, left: spacing/2, bottom: 0, right: -spacing/2)
            break;
        case .bottom:
            imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: -labelHeight!-spacing/2, right: -labelWidth)
            labelEdgeInsets = UIEdgeInsets(top: -imageHeight!-spacing/2, left: -imageWidth!, bottom: 0, right: 0)
            break;
        case .right:
            imageEdgeInsets = UIEdgeInsets(top: 0, left: labelWidth+spacing/2, bottom: 0, right: -labelWidth-spacing/2)
            labelEdgeInsets = UIEdgeInsets(top: 0, left: -imageWidth!-spacing/2, bottom: 0, right: imageWidth!+spacing/2)
            break;
        }
        self.titleEdgeInsets = labelEdgeInsets
        self.imageEdgeInsets = imageEdgeInsets
    }

    
}

// MARK: - 其他
extension UIButton {
    
    /// 根据文字创建按钮
    /// - Parameters:
    ///   - title: 文字
    ///   - font: 字体
    ///   - titleColor: 字体颜色
    /// - Returns: 按钮
    static func buildBtn(title: String, font: UIFont, titleColor: UIColor) -> UIButton {
        let btn = UIButton(frame: .zero)
        btn.backgroundColor = .clear
        btn.setTitle(title, for: .normal)
        btn.setTitleColor(titleColor, for: .normal)
        btn.titleLabel?.font = font
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: 1000, height: 1000))
        label.text = title
        label.textColor = titleColor
        label.font = font
        label.sizeToFit()
//        btn.addSubview(label)
        btn.width = label.width
        btn.height = label.height
        return btn

    }
}


demo参考:github