进阶:UIButton 样式扩展
2021-01-23 本文已影响0人
SoaringHeart
UIButton 添加边框颜色圆角 state 支持;
不继承无侵入;

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)
}
//
// 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 {
removeObserver(self, forKeyPath: "selected")
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"
}
/// 关联UITableView视图对象
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)
}
}
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));
}
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
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