iOS --- 为UIButton添加setBackground

作者: icetime17 | 来源:发表于2016-07-07 21:51 被阅读1032次

有这样的一类简单需求: UIButton的背景色要与其state相关, 如未点击时显示蓝色, 点击时显示绿色.
但是, UIButton自身并未提供setBackgroundColor:forState:方法, 因此我们不得不单独在touchDown等方法中去更新其backgroundColor属性.
这里介绍如何为UIButton提供该扩展方法, Objective-C和Swift的版本都有.
其中用到了runtime的关联对象, 不熟悉的同学可以先参考iOS --- 理解Runtime机制及其使用场景.

Objective-C

Objective-C中通过Category提供该扩展方法.
头文件:

#import <UIKit/UIKit.h>

@interface UIButton (CS_BackgroundColor)

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

@end

实现文件:

#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]; // 注意, 这里的默认背景色必须设置, 仅仅通过下一行暂时不能设置初始的背景色
[btn1 setBackgroundColor:[UIColor greenColor] forState:UIControlStateNormal];
[btn1 setBackgroundColor:[UIColor blueColor] forState:UIControlStateHighlighted];

Swift

Swift的语法终归是要不断练习. 通过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() // 这里的设置同样是必需的.
btn.cs_setBackgroundColor(UIColor.greenColor(), forState: .Normal)
btn.cs_setBackgroundColor(UIColor.blueColor(), forState: .Highlighted)

Demo

Objective-C版本的Demo请参考DemoRuntime.
Swift版本的Demo请参考CSSwiftExtension.

相关文章

网友评论

  • 00f0453d6767:其实只要一张纯色的图片做背景就好了
    self.setBackgroundImage(UIImage.init(color: bgDisabledColor), for: .disabled)
    00f0453d6767:纯色图片方法
    public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
    let rect = CGRect(origin: .zero, size: size)
    UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
    color.setFill()
    UIRectFill(rect)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    guard let cgImage = image?.cgImage else { return nil }
    self.init(cgImage: cgImage)
    }
  • icetime17:实践证明,使用runtime来设置UIButton的backgroundColor的方式,会出现setImage出错的情况。所以,正确设置backgroundColor的姿势请参考:https://github.com/icetime17/CSSwiftExtension

    btnTest.cs.setBackgroundColor(UIColor.blue, for: .normal) // set backgroundColor
    btnTest.cs.setBackgroundColor(UIColor.red, for: .highlighted)

本文标题:iOS --- 为UIButton添加setBackground

本文链接:https://www.haomeiwen.com/subject/gwvljttx.html