UIButtonConfiguration

前言

随着iOS的更新,大的变动似乎没有,小的变动却很多。而且国内的开发者和国外的有一个很大的不同点,就是国内的求稳,国外的求创新。我接手过的几个项目,最低支持的还有iOS7的,普遍的都是iOS8、9。代码很少会考虑到iOS12,13以上的新特性。2022年4月25号,苹果强制打包的SDK必须升级到iOS15,之前是警告我都没在意,现在成错误了。最开始我还以为可以像添加真机调试包那样不用升级XCode就可以,后来发现我想多了。必须升级XCode13,升级XCode的过程也是一波三折。XCode13.2.1必须要MacOS Big Sur(MacOS 11),我的电脑是12年的mini,然后各种求救,发现可以通过打补丁升级。反正折腾了一天,搞好了之后升级然后发现项目出现各种各样的UIbug,什么导航栏透明变白的,UIBarButtonItem的颜色出现问题啊,TabBar也出现问题。弄好了之后。我就发现了一个问题。苹果的代码风格变了,如果你写过Flutter或者用过SwiftUI,你就越发觉得苹果的代码设计风格变了,特别是在UIKit里,频繁的出现了一个词Configuartion,像UILabel,UITabbar,UIButton,UINavigationBar等等。都有与之对应的Configuration对象。甚至像基础类型UIColor,backgroundColor都有与之对应的Configuration对象。这样的设计风格初看有些繁琐,但用的多了,反而很顺手,这种设计模式就是23种设计模式中的装饰模式。

UIButtonConfiguration作用的UI元素

UIButtonConfiguration既然是装饰模式的一种实践,那么它必然只会对UI元素做集成,像消息传递、手势、动作、它是不参与的,颜色文本图片背景样式的,它都可以涉及到。

API详述

弄清楚一个类的成员属性和方法,就是写个案例试一下。这样是最快的,比google和百度都好的多。但也仅限于UI类。像一些抽象类,工具类查文档更适合。

1. 初始化方法

///主要生成扁平纯净的ButtonConfiguration,不设置额外属性
+ (instancetype)plainButtonConfiguration;

///着色类ButtonConfiguration,主要特点是背景色会半透明化,比如设置yellowColor的背景色,而背景的颜色呈现半透明黄色
+ (instancetype)tintedButtonConfiguration;

///半透明灰色背景按钮,设置自定义basebackgroundColor会改变背景色,也就是它的优先级低一点。
+ (instancetype)grayButtonConfiguration;

///填充类ButtonConfiguration,它的效果和plainButtonConfiguration类似(暂时未发现不同)
+ (instancetype)filledButtonConfiguration;

///强制无边框圆角类ButtonConfiguration,它的优先级最高,如果你设置了btn.layer.cornerRadius, 或者config.background也设置了圆角或者设置了config.cornerStyle都不会出现圆角。
+ (instancetype)borderlessButtonConfiguration;

///内置设置了一个圆角为5左右的ButtonConfiguration,但优先级小于btn.layer.cornerRadius
+ (instancetype)borderedButtonConfiguration;

///圆角半透明背景的ButtonConfiguration
+ (instancetype)borderedTintedButtonConfiguration;

///圆角个性化ButtonConfiguration,主要体现在背景色不透明,文字和图片着色和背景色相反(例如黑色背景,白色文字或者白色背景,黑色文字等)。这一前提在于不主动设置文字颜色和图片颜色的前提。一般情况下,如果不设置文字和图片颜色,它们的颜色则为系统默认的系统蓝色。
+ (instancetype)borderedProminentButtonConfiguration;

///init和new方法是不允许使用的
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;

///这个方法,根据说明是复制指定button的ButtonConfiguration。但有一个疑问,这个是实例方法。我试了一下,它并不能复制指定状态的configuration,比如normal状态是ConfigA,selected状态是configB,但复制只会复制normal状态的值,这和直接btn.configuration = config貌似没有什么区别,可能是我研究不深,没有发现它们的区别
- (instancetype)updatedConfigurationForButton:(UIButton *)button;

2. 属性变量

///这个是一个关于background相关的config对象,他能处理的内容太多了,背景色,圆角,边框,阴影,自定义绘图(贝塞尔曲线绘图等),毛玻璃特效,背景图片等。只要和背景相关的UI元素,基本都能处理。
@property (nonatomic, readwrite, strong) UIBackgroundConfiguration *background;

///圆角风格枚举
-1,固定圆角,0:动态圆角这两个值其实差不多,就是圆角值可以通过btn.layer.cornerRadius和config.background.cornerRadius两种方式设置。1、2、3这三个值代表内置的小、中、大三个内置的圆角,他的优先级比btn.layer.cornerRadius和config.background.cornerRadius 高,4是胶囊风格,就是圆角切成胶囊状,优先级和1、2、3一样。
@property (nonatomic, readwrite, assign) UIButtonConfigurationCornerStyle cornerStyle;

///内置的title字体大小,优先级比attributedTitle低,也就是你不想自己设置title和Subtitle字体大小时可以用这个枚举来参考设置,一般来讲如果自己的UI设计和审美不怎么样,或者无所谓时用一用系统推荐的也不错,毕竟苹果的审美你没法说别人不好吧。
@property (nonatomic, readwrite, assign) UIButtonConfigurationSize buttonSize;

///看字面意思就是适配mac端的按钮样式。
@property (nonatomic, readwrite, assign) UIButtonConfigurationMacIdiomStyle macIdiomStyle;

///文本颜色,title和Subtitle,根据文档,它的优先级比attributedTitleattributedSubtitle以及它俩的变形器都低。它是一个全局设置变量,当你想按钮任何状态文本颜色不变时,可以设置这个值
@property (nonatomic, readwrite, strong, nullable) UIColor *baseForegroundColor;

///背景色,同理它的优先级比background低。
@property (nonatomic, readwrite, strong, nullable) UIColor *baseBackgroundColor;

///图片
@property (nonatomic, readwrite, strong, nullable) UIImage *image;

///图片颜色变形器,他是一个输入颜色,再输出颜色的回调,目前不清楚设置成回调的好处,反正你在回调里直接返回你想要设置的颜色即可
@property (nonatomic, readwrite, copy, nullable) UIConfigurationColorTransformer imageColorTransformer;

///内置的系统矢量图图标config对象,你可以设置指定风格,大小,颜色的矢量图图标作为按钮的image
@property (nonatomic, readwrite, copy, nullable) UIImageSymbolConfiguration *preferredSymbolConfigurationForImage;

///是否显示加载转圈的HUD图标(菊花指示器),HUD的位置和image是一致的,且hud和image不能同时存在
@property (nonatomic, readwrite, assign) BOOL showsActivityIndicator;

///加载HUD指示器的颜色变形器
@property (nonatomic, readwrite, copy, nullable) UIConfigurationColorTransformer activityIndicatorColorTransformer;

///主标题的文本,富文本及变形器
@property (nonatomic, readwrite, copy, nullable) NSString *title; @property (nonatomic, readwrite, copy, nullable) NSAttributedString *attributedTitle; @property (nonatomic, readwrite, copy, nullable) UIConfigurationTextAttributesTransformer titleTextAttributesTransformer;

///副标题的文本,富文本及变形器
@property (nonatomic, readwrite, copy, nullable) NSString *subtitle; @property (nonatomic, readwrite, copy, nullable) NSAttributedString *attributedSubtitle; @property (nonatomic, readwrite, copy, nullable) UIConfigurationTextAttributesTransformer subtitleTextAttributesTransformer;

///内容四边距
@property (nonatomic, readwrite, assign) NSDirectionalEdgeInsets contentInsets;

///恢复默认边距
- (void)setDefaultContentInsets;

///图标放置方位,这是一个非常好用的属性,在这之前,如果你想制作右图左文,上图下文的图标,你得设置imageInset和titleInset,关键还要计算文本的size和图标的size。如果你的按钮通过AutoLayout布局,那么这将计算更加困难,你必须将UIButton子类化,在-layoutSubviews方法中调整,不然无法获取titleLabel和imageView的正确尺寸。现在有了这个属性再配合imagePadding一切变得那么美好了,亲爱的(grd)苹果的工程师,为什么不早点拿出来啊?有一点需要说明,这是个option枚举,意思是可以多选,但实际应用,并不能达到效果,比如你想图标在右上角,你将值设置为NSDirectionalRectEdgeTop|NSDirectionalRectEdgeTrailing实际上按钮还是Y轴居中,右边显示,没有啥效果,目前不明啥原因,我猜测可能需要配合UIButton的对齐属性使用才有效果。
@property (nonatomic, readwrite, assign) NSDirectionalRectEdge imagePlacement;

///图标距文本的距离
@property (nonatomic, readwrite, assign) CGFloat imagePadding;

///标题与子标题的间距,可以为负值
@property (nonatomic, readwrite, assign) CGFloat titlePadding;

///按钮文本对齐风格
@property (nonatomic, readwrite, assign) UIButtonConfigurationTitleAlignment titleAlignment;

///选中状态时是否更新buttonConfigration,实际用不到,下面会体现
@property (nonatomic, readwrite, assign) BOOL automaticallyUpdateForSelection;

///下面是UIButton的属性,这个也是核心,根据按钮不同的状态切换不同的buttonConfiguration,值得注意的是每个分支结尾必须重新赋值,示例如下

btn.configurationUpdateHandler = ^(UIButton *b) {
        if (b.state == UIControlStateHighlighted) {
            btnConfig.showsActivityIndicator = YES;
            btnConfig.attributedTitle = [[NSAttributedString alloc] initWithString:@"Highlighted Title" attributes:@{NSForegroundColorAttributeName:[UIColor systemRedColor]}];
            btnConfig.attributedSubtitle = [[NSAttributedString alloc] initWithString:@"Highlighted Subtitle" attributes:@{NSForegroundColorAttributeName:[UIColor systemRedColor]}];
            btnConfig.image = [UIImage systemImageNamed:@"square.and.arrow.up.fill"];
            btnConfig.imageColorTransformer = ^UIColor * _Nonnull(UIColor * _Nonnull color) {
                return [UIColor systemPurpleColor];
            };
            ///这个赋值操作必须写,不然不生效
            b.configuration = btnConfig;
        }else {
            btnConfig.showsActivityIndicator = NO;
            btnConfig.attributedTitle = [[NSAttributedString alloc] initWithString:@"Normal Title" attributes:@{NSForegroundColorAttributeName:[UIColor systemRedColor]}];
            btnConfig.attributedSubtitle = [[NSAttributedString alloc] initWithString:@"Normal Subtitle" attributes:@{NSForegroundColorAttributeName:[UIColor systemRedColor]}];
            btnConfig.image = [UIImage systemImageNamed:@"square.and.arrow.up"];
            btnConfig.imageColorTransformer = ^UIColor * _Nonnull(UIColor * _Nonnull color) {
                return [UIColor systemOrangeColor];
            };
            ///这个赋值操作必须写,不然不生效
            b.configuration = btnConfig;
        }
    };

还有一个要注意的点

///这行代码生效
btnConfig.baseForegroundColor = [UIColor systemGreenColor];
 btn.configuration = btnConfig;
///这行代码不生效
btnConfig.baseForegroundColor = [UIColor systemRedColor];

总结

UIButtonConfiguration的优点在我看来有以下几点

  1. 使用装饰模式,让责任区分更加明确。
  2. 更多内置样式,在某些场景使用更方便。
  3. API扩展性更强大了,这可能是最重要的一点了。给按钮加自定义背景视图,比如毛玻璃,多彩渐变等。给按钮添加加载指示器。调整按钮的图文布局等,在以前的环境的下,要添加大量代码。而现在变得更加简单了。

唯一的缺点是版本要求太高,无法兼容低版本。

你可能感兴趣的:(UIButtonConfiguration)