UIButton added border color rounded corner state support;

No inheritance, no intrusion;

Swift

🌰🌰 : let sender = UIButton(type:.custom); sender.setBorderColor(.lightGray, for: .normal) sender.setBorderColor(.systemBlue, for: .selected) sender.setCornerRadius(4, for: .normal) sender.setCornerRadius(14, for: .selected) sender.addTarget(self, action: #selector(handActionBtn(_:)), for: .touchUpInside) @objc func handActionBtn(_ sender: NNButton) { sender.isSelected = ! sender.isSelected DDLog(sender.frame, sender.titleLabel?.frame) }Copy the code
// // UIButton+Layer.swift // SwiftTemplet // // Created by Bin Shang on 2021/1/23. // Copyright © 2021 Bn. All Rights reserved. // import UIKit class NNButtonLayerTarget: NSObject { public weak var button: UIButton? ///addObserver(self, forKeyPath: "selected", options: .new, context: nil) var observerBlock:((String? , UIButton? , [NSKeyValueChangeKey: Any]?) ->Void)? var borderColorDic = [UIControl.State.RawValue: UIColor]() var borderWidthDic = [UIControl.State.RawValue: CGFloat]() var cornerRadiusDic = [UIControl.State.RawValue: CGFloat]() // MARK: -lifecycle deinit { button? .removeObserver(self, forKeyPath: "selected") button? .removeObserver(self, forKeyPath: "highlighted") } // MARK: -observe override func observeValue(forKeyPath keyPath: String? , of object: Any? , change: [NSKeyValueChangeKey : Any]? , context: UnsafeMutableRawPointer?) { if let sender = object as? UIButton { if keyPath == "selected" || keyPath == "highlighted" { changeLayerBorderColor(sender) changeLayerBorderWidth(sender) changeLayerCornerRadius(sender) observerBlock? (keyPath, sender, change) } } else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) } } // MARK: -public func setBorderColor(_ color: UIColor? , for state: UIControl.State){ guard let color = color else { return } borderColorDic[state.rawValue] = color changeLayerBorderColor(button) } func borderColor(for state: UIControl.State) -> UIColor? { return borderColorDic[state.rawValue] } func setBorderWidth(_ value: CGFloat, for state: UIControl.State){ borderWidthDic[state.rawValue] = value changeLayerBorderWidth(button) } func borderWidth(for state: UIControl.State) -> CGFloat{ return borderWidthDic[state.rawValue] ?? 0 } func setCornerRadius(_ value: CGFloat, for state: UIControl.State){ cornerRadiusDic[state.rawValue] = value changeLayerCornerRadius(button) } func cornerRadius(for state:  UIControl.State) -> CGFloat{ return cornerRadiusDic[state.rawValue] ?? 0 } // MARK: -private private func changeLayerBorderColor(_ sender: UIButton?) { guard let sender = sender, let normalColor = borderColorDic[UIControl.State.normal.rawValue] else { return } let color = borderColorDic[sender.state.rawValue] ?? normalColor sender.layer.borderColor = color.cgColor if sender.layer.borderWidth == 0 { sender.layer.borderWidth = 1 } }  private func changeLayerBorderWidth(_ sender: UIButton?) { guard let sender = sender, let normalValue = borderWidthDic[UIControl.State.normal.rawValue] else { return } let value = borderWidthDic[sender.state.rawValue] ?? normalValue sender.layer.borderWidth = value if sender.layer.borderWidth == 0 { sender.layer.borderWidth = 1 } } private  func changeLayerCornerRadius(_ sender: UIButton?) { guard let sender = sender, let normalValue = cornerRadiusDic[UIControl.State.normal.rawValue] else { return } let value = cornerRadiusDic[sender.state.rawValue] ?? normalValue sender.layer.cornerRadius = value if sender.layer.borderWidth == 0 { sender.layer.borderWidth = 1 } } } public extension UIButton{ private struct AssociateKeys { static var layerTarget = "UIButton" + "layerTarget" } /// Associated UITableView object private var layerTarget: NNButtonLayerTarget { get { if let obj = objc_getAssociatedObject(self, &AssociateKeys.layerTarget) as? NNButtonLayerTarget { return obj } let target = NNButtonLayerTarget() target.button = self target.button? .addObserver(target, forKeyPath: "selected", options: .new, context: nil) target.button? .addObserver(target, forKeyPath: "highlighted", options: .new, context: nil) objc_setAssociatedObject(self, &AssociateKeys.layerTarget, target, .OBJC_ASSOCIATION_RETAIN_NONATOMIC); return target } } func setBorderColor(_ color: UIColor? , for state: UIControl.State){ layerTarget.setBorderColor(color, for: state) } func borderColor(for state: UIControl.State) -> UIColor? { return layerTarget.borderColor(for: state) } func setBorderWidth(_ value: CGFloat, for state: UIControl.State){ layerTarget.setBorderWidth(value, for: state) } func borderWidth(for state: UIControl.State) -> CGFloat? { return layerTarget.borderWidth(for: state) } func setCornerRadius(_ value: CGFloat, for state: UIControl.State){ layerTarget.setCornerRadius(value, for: state) } func cornerRadius(for state: UIControl.State) -> CGFloat? { return layerTarget.cornerRadius(for: state) } }Copy the code

OC

🌰🌰 : //@property (nonatomic, strong) UIButton *button1; - (UIButton *)button1{ if (! _button1) { _button1 = ({ UIButton *sender = [UIButton buttonWithType:UIButtonTypeCustom]; [sender setTitle:@"Normal" forState:UIControlStateNormal]; [sender setTitle:@"Selected" forState:UIControlStateSelected]; [sender setTitleColor:UIColor.systemGrayColor forState:UIControlStateNormal]; [sender setTitleColor:UIColor.systemBlueColor forState:UIControlStateSelected]; sender.titleLabel.font = [UIFont systemFontOfSize:15]; // sender.titleLabel.adjustsFontSizeToFitWidth = YES; sender.imageView.contentMode = UIViewContentModeScaleAspectFit; sender; }); [_button1 setBorderColor:UIColor.lightGrayColor forState:UIControlStateNormal]; [_button1 setBorderColor:UIColor.systemBlueColor forState:UIControlStateSelected]; [_button1 setCornerRadius:4 forState:UIControlStateNormal]; [_button1 setCornerRadius:14 forState:UIControlStateSelected]; [_button1 addTarget:self action:@selector(handleAction:) forControlEvents:UIControlEventTouchUpInside]; } return _button1; } #pragma mark -funtions - (void)handleAction:(UIButton *)sender{ sender.selected = ! sender.selected; // DDLog(@"isSelected_%@", @(sender.isSelected)); }Copy the code

UIButton+Border.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIButton (BorderColor)

- (void)setBorderColor:(nullable UIColor *)color forState:(UIControlState)state;
- (nullable UIColor *)borderColorForState:(UIControlState)state;

- (void)setBorderWidth:(CGFloat)value forState:(UIControlState)state;
- (CGFloat)borderWidthForState:(UIControlState)state;
    
- (void)setCornerRadius:(CGFloat)value forState:(UIControlState)state;
- (CGFloat)cornerRadiusForState:(UIControlState)state;

@end

NS_ASSUME_NONNULL_END
Copy the code

UIButton+Border.m

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

@interface NNBorderTarget : NSObject

@property (nonatomic, weak) UIButton *button;

@property (nonatomic, strong) NSMutableDictionary<NSNumber *, UIColor *> *borderColorDic;
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, NSNumber *> *borderWidthDic;
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, NSNumber *> *cornerRadiusDic;

- (void)setBorderColor:(nullable UIColor *)color forState:(UIControlState)state;
- (nullable UIColor *)borderColorForState:(UIControlState)state;

- (void)setBorderWidth:(CGFloat)value forState:(UIControlState)state;
- (CGFloat)borderWidthForState:(UIControlState)state;
    
- (void)setCornerRadius:(CGFloat)value forState:(UIControlState)state;
- (CGFloat)cornerRadiusForState:(UIControlState)state;

@end


@implementation NNBorderTarget

- (void)dealloc{
    [self.button removeObserver:self forKeyPath:@"selected"];
    [self.button removeObserver:self forKeyPath:@"highlighted"];
}

#pragma mark -observe
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if ([object isKindOfClass:[UIButton class]]) {
        UIButton *sender = (UIButton *)object;
        if ([keyPath isEqualToString:@"selected"] || [keyPath isEqualToString:@"highlighted"]) {
            [self changeLayerBorderColor: sender];
            [self changeLayerBorderWidth: sender];
            [self changeLayerCornerRadius: sender];
        }
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}


#pragma mark -set,get
- (NSMutableDictionary<NSNumber *,UIColor *> *)borderColorDic{
    if (!_borderColorDic) {
        _borderColorDic = @{
            
        }.mutableCopy;
    }
    return _borderColorDic;
}

- (NSMutableDictionary<NSNumber *, NSNumber *> *)borderWidthDic{
    if (!_borderWidthDic) {
        _borderWidthDic = @{
            
        }.mutableCopy;
    }
    return _borderWidthDic;
}

- (NSMutableDictionary<NSNumber *, NSNumber *> *)cornerRadiusDic{
    if (!_cornerRadiusDic) {
        _cornerRadiusDic = @{
            
        }.mutableCopy;
    }
    return _cornerRadiusDic;
}

#pragma mark -public

- (void)setBorderColor:(nullable UIColor *)color forState:(UIControlState)state{
    if (!color) {
        return;
    }
    self.borderColorDic[@(state)] = color;
    [self changeLayerBorderColor: self.button];
}

- (nullable UIColor *)borderColorForState:(UIControlState)state{
    return self.borderColorDic[@(state)];
}

- (void)setBorderWidth:(CGFloat)value forState:(UIControlState)state{
    self.borderWidthDic[@(state)] = @(value);
    [self changeLayerBorderWidth: self.button];
}

- (CGFloat)borderWidthForState:(UIControlState)state{
    return self.borderWidthDic[@(state)].floatValue;
}

- (void)setCornerRadius:(CGFloat)value forState:(UIControlState)state{
    self.cornerRadiusDic[@(state)] = @(value);
    [self changeLayerCornerRadius: self.button];
}

- (CGFloat)cornerRadiusForState:(UIControlState)state{
    return self.cornerRadiusDic[@(state)].floatValue;
}

#pragma mark -private
- (void)changeLayerBorderColor:(UIButton *)sender{
    UIColor *normalColor = self.borderColorDic[@(UIControlStateNormal)];
    if (!normalColor) {
        return;
    }

    UIColor *color = self.borderColorDic[@(sender.state)] ? : normalColor;
    sender.layer.borderColor = color.CGColor;
    
    if (sender.layer.borderWidth == 0) {
        sender.layer.borderWidth = 1;
    }
}

- (void)changeLayerBorderWidth:(UIButton *)sender{
    NSNumber *normalValue = self.borderWidthDic[@(UIControlStateNormal)];
    if (!normalValue) {
        return;
    }
    
    NSNumber *numer = self.borderWidthDic[@(sender.state)] ? : normalValue;
    sender.layer.borderWidth = numer.floatValue;
    
    if (sender.layer.borderWidth == 0) {
        sender.layer.borderWidth = 1;
    }
}

- (void)changeLayerCornerRadius:(UIButton *)sender{
    NSNumber *normalValue = self.cornerRadiusDic[@(UIControlStateNormal)];
    if (!normalValue) {
        return;
    }
    
    NSNumber *numer = self.cornerRadiusDic[@(sender.state)] ? : normalValue;
    sender.layer.cornerRadius = numer.floatValue;
    
    if (sender.layer.borderWidth == 0) {
        sender.layer.borderWidth = 1;
    }
}

@end



@implementation UIButton (Border)

- (NNBorderTarget *)borderTarget{
    id obj = objc_getAssociatedObject(self, _cmd);
    if (obj) {
        return obj;
    }
    NNBorderTarget *target = [[NNBorderTarget alloc]init];
    target.button = self;
    
    [target.button addObserver:target forKeyPath:@"selected" options:NSKeyValueObservingOptionNew context:nil];
    [target.button addObserver:target forKeyPath:@"highlighted" options:NSKeyValueObservingOptionNew context:nil];

    objc_setAssociatedObject(self, @selector(borderTarget), target, OBJC_ASSOCIATION_RETAIN);
    return target;
}

- (void)setBorderColor:(nullable UIColor *)color forState:(UIControlState)state{
    [self.borderTarget setBorderColor:color forState:state];
}

- (nullable UIColor *)borderColorForState:(UIControlState)state{
    return [self.borderTarget borderColorForState:state];
}

- (void)setBorderWidth:(CGFloat)value forState:(UIControlState)state{
    [self.borderTarget setBorderWidth:value forState:state];
}

- (CGFloat)borderWidthForState:(UIControlState)state{
    return [self.borderTarget borderWidthForState:state];
}

- (void)setCornerRadius:(CGFloat)value forState:(UIControlState)state{
    [self.borderTarget setCornerRadius:value forState:state];
}

- (CGFloat)cornerRadiusForState:(UIControlState)state{
    return [self.borderTarget cornerRadiusForState:state];
}

@end

Copy the code