UIButtonConfiguration

作者: championfu | 来源:发表于2022-06-02 11:57 被阅读0次

    前言

    随着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

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