iOS --- 為UIButton添加setBackgroundColor:forState:方法(包含OC和Swift兩個版本)

有這樣的一類簡單需求: UIButton的背景色要與其state相關(guān), 如未點擊時顯示藍(lán)色, 點擊時顯示綠色.
但是, UIButton自身并未提供setBackgroundColor:forState:方法, 因此我們不得不單獨(dú)在touchDown等方法中去更新其backgroundColor屬性.
這里介紹如何為UIButton提供該擴(kuò)展方法, Objective-C和Swift的版本都有.
其中用到了runtime的關(guān)聯(lián)對象, 不熟悉的同學(xué)可以先參考iOS --- 理解Runtime機(jī)制及其使用場景.

Objective-C

Objective-C中通過Category提供該擴(kuò)展方法.
頭文件:

#import <UIKit/UIKit.h>

@interface UIButton (CS_BackgroundColor)

- (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state;

@end

實現(xiàn)文件:

#import "UIButton+CS_BackgroundColor.h"
#import <objc/runtime.h>

@interface UIButton (CS_BackgroundColor)

@property (nonatomic, strong) NSMutableDictionary *cs_dictBackgroundColor;

@end


@implementation UIButton (CS_BackgroundColor)

static const NSString *key_cs_backgroundColor             = @"key_cs_backgroundColor";

static NSString *cs_stringForUIControlStateNormal         = @"cs_stringForUIControlStateNormal";
static NSString *cs_stringForUIControlStateHighlighted    = @"cs_stringForUIControlStateHighlighted";
static NSString *cs_stringForUIControlStateDisabled       = @"cs_stringForUIControlStateDisabled";
static NSString *cs_stringForUIControlStateSelected       = @"cs_stringForUIControlStateSelected";

#pragma mark - cs_dictBackgroundColor

- (NSMutableDictionary *)cs_dictBackgroundColor {
    return objc_getAssociatedObject(self, &key_cs_backgroundColor);
}

- (void)setCs_dictBackgroundColor:(NSMutableDictionary *)cs_dictBackgroundColor {
    objc_setAssociatedObject(self, &key_cs_backgroundColor, cs_dictBackgroundColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state {
    if (!self.cs_dictBackgroundColor) {
        self.cs_dictBackgroundColor = [[NSMutableDictionary alloc] init];
    }

    [self.cs_dictBackgroundColor setObject:backgroundColor forKey:[self cs_stringForUIControlState:state]];
}

- (NSString *)cs_stringForUIControlState:(UIControlState)state {
    NSString *cs_string;
    switch (state) {
        case UIControlStateNormal:
            cs_string = cs_stringForUIControlStateNormal;
            break;
        case UIControlStateHighlighted:
            cs_string = cs_stringForUIControlStateHighlighted;
            break;
        case UIControlStateDisabled:
            cs_string = cs_stringForUIControlStateDisabled;
            break;
        case UIControlStateSelected:
            cs_string = cs_stringForUIControlStateSelected;
            break;
        default:
            cs_string = cs_stringForUIControlStateNormal;
            break;
    }
    return cs_string;
}

#pragma mark - highlighted

- (void)setHighlighted:(BOOL)highlighted {
    if (highlighted) {
        self.backgroundColor = (UIColor *)[self.cs_dictBackgroundColor objectForKey:cs_stringForUIControlStateHighlighted];
    } else {
        self.backgroundColor = (UIColor *)[self.cs_dictBackgroundColor objectForKey:cs_stringForUIControlStateNormal];
    }
}

@end

使用方法:

btn1.backgroundColor = [UIColor greenColor]; // 注意, 這里的默認(rèn)背景色必須設(shè)置, 僅僅通過下一行暫時不能設(shè)置初始的背景色
[btn1 setBackgroundColor:[UIColor greenColor] forState:UIControlStateNormal];
[btn1 setBackgroundColor:[UIColor blueColor] forState:UIControlStateHighlighted];

Swift

Swift的語法終歸是要不斷練習(xí). 通過extension來提供該方法.

public extension UIButton {

    private struct cs_backgroundColor {
        static var keyBackgroundColors              = "cs_keyBackgroundColors"

        static var keyBackgroundColor_Normal        = "cs_keyBackgroundColor_Normal"
        static var keyBackgroundColor_Highlighted   = "cs_keyBackgroundColor_Highlighted"
    }

    var cs_dictBackgroundColors: Dictionary<String, UIColor>! {
        get {
            if let dictBackgroundColors = objc_getAssociatedObject(self, &cs_backgroundColor.keyBackgroundColors) {
                return dictBackgroundColors as! Dictionary<String, UIColor>
            }

            return nil
        }

        set {
            objc_setAssociatedObject(self, &cs_backgroundColor.keyBackgroundColors, newValue as Dictionary<String, UIColor>, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    func cs_setBackgroundColor(color: UIColor, forState: UIControlState) {
        if self.cs_dictBackgroundColors == nil {
            self.cs_dictBackgroundColors = Dictionary<String, UIColor>()
        }

        if let key = self.cs_stringForUIControlState(forState) {
            self.cs_dictBackgroundColors[key] = color
        }
    }

    private func cs_stringForUIControlState(state: UIControlState) -> String! {
        var cs_string = ""

        switch state {
        case UIControlState.Normal:
            cs_string = cs_backgroundColor.keyBackgroundColor_Normal
        case UIControlState.Highlighted:
            cs_string = cs_backgroundColor.keyBackgroundColor_Highlighted
        default:
            cs_string = cs_backgroundColor.keyBackgroundColor_Normal
        }

        return cs_string
    }

    override var highlighted: Bool {
        get {
            return super.highlighted
        }

        set {
            if newValue {
                if let key = self.cs_stringForUIControlState(.Highlighted) {
                    self.backgroundColor = self.cs_dictBackgroundColors[key]!
                }
            } else {
                if let key = self.cs_stringForUIControlState(.Normal) {
                    self.backgroundColor = self.cs_dictBackgroundColors[key]!
                }
            }
        }
    }

}

使用方法:

btn.backgroundColor = UIColor.greenColor() // 這里的設(shè)置同樣是必需的.
btn.cs_setBackgroundColor(UIColor.greenColor(), forState: .Normal)
btn.cs_setBackgroundColor(UIColor.blueColor(), forState: .Highlighted)

Demo

Objective-C版本的Demo請參考DemoRuntime.
Swift版本的Demo請參考CSSwiftExtension.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市替饿,隨后出現(xiàn)的幾起案子语泽,更是在濱河造成了極大的恐慌,老刑警劉巖视卢,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踱卵,死亡現(xiàn)場離奇詭異,居然都是意外死亡据过,警方通過查閱死者的電腦和手機(jī)惋砂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绳锅,“玉大人西饵,你說我怎么就攤上這事×圮剑” “怎么了眷柔?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長积蜻。 經(jīng)常有香客問我闯割,道長彻消,這世上最難降的妖魔是什么竿拆? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮宾尚,結(jié)果婚禮上丙笋,老公的妹妹穿的比我還像新娘。我一直安慰自己煌贴,他們只是感情好御板,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著牛郑,像睡著了一般怠肋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淹朋,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天笙各,我揣著相機(jī)與錄音钉答,去河邊找鬼。 笑死杈抢,一個胖子當(dāng)著我的面吹牛数尿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惶楼,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼右蹦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了歼捐?” 一聲冷哼從身側(cè)響起何陆,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎豹储,沒想到半個月后甲献,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颂翼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年晃洒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朦乏。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡球及,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呻疹,到底是詐尸還是另有隱情吃引,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布刽锤,位于F島的核電站镊尺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏并思。R本人自食惡果不足惜庐氮,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望宋彼。 院中可真熱鬧弄砍,春花似錦、人聲如沸输涕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽莱坎。三九已至衣式,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碴卧。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工碉京, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人螟深。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓谐宙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親界弧。 傳聞我的和親對象是個殘疾皇子凡蜻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容