Swift-自定義控件之IndicatorButton(帶動畫的按鈕)

Swift-自定義控件之IndicatorButton(帶動畫的按鈕)

應用場景

登錄或者注冊時,點擊按鈕發(fā)送請求,此時禁用按鈕,并且按鈕上加載菊花,提示用戶需要等待,請求回調(diào)之后隱藏菊花……

實現(xiàn)思路

  • 初步嘗試:動畫修改按鈕的title位置不是那么容易(或者說我沒找到合適的方法)
  • 最終方案:在按鈕上添加子控件,動畫隱藏或顯示子控件和title

代碼實現(xiàn)

新建類

// 繼承自UIButton
public class IndicatorButton: UIButton {
}

構(gòu)造方法

// MARK: - 構(gòu)造方法
required public init?(coder decoder: NSCoder) {
    super.init(coder: decoder)
    // 初始化
    setup()
}

init() {
    super.init(frame: CGRectZero)
    // 初始化
    setup()
}

公共屬性

// MARK: - 公開屬性
/// 標識是否是向下切換title
var upToDown: Bool = false
/// borderColor
var borderColor: UIColor = UIColor.clearColor() {
    didSet {
        layer.borderColor = borderColor.CGColor
    }
}
/// borderWidth
var borderWidth: CGFloat = 0 {
    didSet {
        layer.borderWidth = borderWidth
    }
}
/// cornerRadius
var cornerRadius: CGFloat = 0 {
    didSet {
        layer.cornerRadius = cornerRadius
    }
}
public override var enabled: Bool {
    didSet {
        if oldValue != enabled {
            if oldValue {
                // 動畫切換title,顯示菊花
                lastDisabledTitle = titleForState(.Disabled)
                ib_loadingWithTitle(lastDisabledTitle)
                setTitle("", forState: .Disabled)
            } else {
                // 重置按鈕,隱藏菊花
                ib_resetToNormalState()
                setTitle(lastDisabledTitle, forState: .Disabled)
            }
        }
    }
}

私有屬性

// MARK: - 私有屬性
lazy var backView = UIView()
lazy var lblMessage = UILabel()
lazy var indicatorView = UIActivityIndicatorView()
private var lastTitle: String?
private var lastDisabledTitle: String?
private let margin: CGFloat = 8
private var transformY: CGFloat {
    get {
        return self.h * (upToDown ? (-1) : 1)
    }
}

私有方法

// MARK: - 私有方法
// 初始化
private func setup() {
    layer.masksToBounds = true
    // 初始化backView及其子視圖
    lblMessage.textColor = titleLabel?.textColor
    lblMessage.font = titleLabel?.font
    backView.addSubview(lblMessage)
    
    indicatorView.activityIndicatorViewStyle = .White
    indicatorView.hidesWhenStopped = true
    indicatorView.sizeToFit()
    backView.addSubview(indicatorView)
    
    // 要先設置高度  再設置center
    backView.h = self.h
    backView.center = CGPointMake(self.w * 0.5, self.h * 0.5)
    backView.backgroundColor = UIColor.clearColor()
    backView.alpha = 0
    
    addSubview(backView)
    
    lastTitle = currentTitle
}

// 開始轉(zhuǎn)菊花
private func ib_loadingWithTitle(title: String?) {
    let color = self.titleColorForState(.Disabled)
    let shadowColor = self.titleShadowColorForState(.Disabled)
    lblMessage.text = title
    lblMessage.textColor = color
    lblMessage.shadowColor = shadowColor
    lblMessage.sizeToFit()
    // 計算lblMessage 和 indicatorView 的位置
    indicatorView.centerY = backView.centerY
    lblMessage.centerY = indicatorView.centerY
    lblMessage.left = indicatorView.right + margin
    backView.right = lblMessage.right
    backView.w = indicatorView.w + margin + lblMessage.w
    backView.left = (self.w - backView.w ) * 0.5
    
    indicatorView.startAnimating()
    if title == lastTitle {
        // 如果title和舊title相同  不需要顯示動畫滾動
    } else {
        backView.transform=CGAffineTransformMakeTranslation(0, transformY)
    }
    UIView.animateWithDuration(0.5) {
        self.titleLabel!.alpha = 0
        self.backView.alpha = 1
        self.backView.transform = CGAffineTransformIdentity
    }
}

// 重置按鈕
private func ib_resetToNormalState() {
    UIView.animateWithDuration(0.5, animations: {
        self.titleLabel!.alpha = 1
        self.backView.alpha = 0
        if self.currentTitle == self.lastDisabledTitle {
            // 如果title和舊title相同  不需要顯示動畫滾動
        } else {
            self.backView.transform = CGAffineTransformMakeTranslation(0, self.transformY)
        }
    }) { (finished) in
        self.backView.transform = CGAffineTransformIdentity
        self.indicatorView.stopAnimating()
    }
}

示例調(diào)用

override func viewDidLoad() {
    super.viewDidLoad()
    // 設置圓角半徑
    btnTest.cornerRadius = 3
    // 切換title動畫方式
    btnTest.upToDown = false
    self.btnTest.setTitle("登錄", forState: .Normal)
    self.btnTest.setTitle("登錄中...", forState: .Disabled)
    // FIXME: 注意內(nèi)存泄露?。?!
    btnTest.rac_signalForControlEvents(.TouchUpInside).subscribeNext { [weak self](sender) in
        // 開啟動畫,轉(zhuǎn)菊花
        self?.btnTest.enabled = false
        // 5秒后結(jié)束動畫,隱藏菊花
        let delayInSeconds = 5.0
        let popTime = dispatch_time(DISPATCH_TIME_NOW,
            Int64(delayInSeconds * Double(NSEC_PER_SEC)))
        dispatch_after(popTime, dispatch_get_main_queue()) {
            // 隱藏菊花
            self?.btnTest.enabled = true
            self?.btnTest.setTitle("登錄成功,頁面該跳轉(zhuǎn)了", forState: .Normal)
        }
    }
}

效果圖

IndicatorButton演示.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,115評論 25 709
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 15,410評論 4 61
  • 晚上回家,看到有賣新鮮桔子的,一個個青油油的、略微帶點黃的橢圓形桔子還長在青翠的枝枝葉葉上,看起來非常不錯。 一問...
    楓紅云天閱讀 533評論 21 17
  • 世界各國鐵路軌距表 世界各國鐵路軌距表 世界各國鐵路軌距分布圖 軌距(Track_Gauge)亦即軌道距離,是鐵路...
    凡的數(shù)據(jù)庫閱讀 21,986評論 0 2
  • 星期四 晴 今天講的是MFC的最后一個ppt,叫多線程程序設計 總之就是為了避免發(fā)送多文件使機器無法響應,因此...
    戰(zhàn)昭辰閱讀 74評論 0 0

友情鏈接更多精彩內(nèi)容