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扩展性更强大了,这可能是最重要的一点了。给按钮加自定义背景视图,比如毛玻璃,多彩渐变等。给按钮添加加载指示器。调整按钮的图文布局等,在以前的环境的下,要添加大量代码。而现在变得更加简单了。

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容