Swift 中的外观代理/UI_APPEARANCE_SELECTOR?

Posted

技术标签:

【中文标题】Swift 中的外观代理/UI_APPEARANCE_SELECTOR?【英文标题】:Appearance proxies / UI_APPEARANCE_SELECTOR in Swift? 【发布时间】:2014-10-02 22:17:38 【问题描述】:

Apple 文档指出:

要参与外观代理 API,请标记您的外观 带有 UI_APPEARANCE_SELECTOR 的标题中的属性选择器。

在 Objective-C 中,可以像这样使用 UI_APPEARANCE_SELECTOR 注释属性:

@property (nonatomic, strong) UIColor *foregroundColor UI_APPEARANCE_SELECTOR;

如何在 Swift 中做同样的事情?

【问题讨论】:

【参考方案1】:

将您的自定义视图属性标记为dynamic

例如:

class YourCustomView: UIView 
    @objc dynamic var subviewColor: UIColor? 
        get  return self.yourSubview.backgroundColor 
        set  self.yourSubview.backgroundColor = newValue 
    
    ...

然后:

YourCustomView.appearance().subviewColor = UIColor.greenColor()

【讨论】:

我需要尝试一下。它是否记录在某处? 据我所知,它没有记录在案,但我试过了,它奏效了。基本上,从 Objective-C 框架动态访问的 Swift 属性应该被标记为动态的。 UI_APPEARANCE_SELECTOR 只是代码补全的编译器注解,对运行时没有影响。检查 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer‌​/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAppeara‌​nce.h 不幸的是,它不适用于 Xcode 8.3.2 ios 9.1 中的 UIBarButton 子类,并且在我设置外观并实例化新的自定义 UIBarButtonSubclass 后导致 UIKit 崩溃 还需要在属性中添加@objc属性才能生效。【参考方案2】:

我没有找到解决方案,但找到了解决方法。 我没有对属性进行注释,而是将它们作为类变量。

private struct StarFillColor  static var _color = UIColor.blackColor() 
internal class var starFillColor: UIColor 
    get  return StarFillColor._color 
    set  StarFillColor._color = newValue 

在我设置所有外观的文件中:

MyClass.starFillColor = UIColor.r(181, g: 60, b: 109) 

希望对大家有所帮助!

【讨论】:

【参考方案3】:

根据以前的答案,这是我实现的 UIView 扩展,用于管理带有视图边框的 UIView 外观,我希望它可以帮助某人:

extension UIView 
    @objc dynamic  var borderColor: UIColor? 
        get 
            if let color = self.layer.borderColor 
                return UIColor(cgColor: color)
             else 
                return nil
            
        
        set(color) 
            self.layer.borderColor = color?.cgColor
        
    

    @objc dynamic  var borderWidth: NSNumber? 
        get  return NSNumber(value: Float(self.layer.borderWidth))
        set(width) 
            self.layer.borderWidth = CGFloat(width?.floatValue ?? 0)
        
    

    @objc dynamic  var cornerRadius: NSNumber? 
        get  return NSNumber(value: Float(self.layer.cornerRadius))
        set(radius) 
            self.layer.cornerRadius = CGFloat(radius?.floatValue ?? 0)
        
    

【讨论】:

【参考方案4】:

在 Swift 中,您不需要(实际上,您不能)用 UI_APPEARANCE_SELECTOR 注释属性。

只需确保您的外观属性访问器方法采用以下形式:

func propertyForAxis1(axis1: IntegerType, axis2: IntegerType, axisN: IntegerType) -> PropertyType
func setProperty(property: PropertyType, forAxis1 axis1: IntegerType, axis2: IntegerType)

来源:Apple Documentation

例如:

func setStarViewColor(color: UIColor) 
    self.backgroundColor = color

然后你可以像这样设置你的外观属性:

MyView.appearance().setStarViewColor(someColor)

我目前在我的 Swift 项目中使用这个解决方案,它可以工作,希望它对你也有帮助。

【讨论】:

嗨,你能把你正在使用的课程贴出来吗!我似乎无法正确调用我的二传手,尝试调用它时我得到一个BAD_ACCESS。我想知道我是否正确地声明了我的类,它是UIButton 的子类,并且我符合UIAppearanceContainer 就像它在文档中所说的那样!干杯! @Rich Checkout 我的gist,包括全班,希望对您有所帮助。 不幸的是,这不允许我更改特定实例的颜色。知道如何实现吗?谢谢! 遗憾的是,对此的回应很晚,但我发现将方法标记为动态解决了 UIButton 的 BAD_ACCESS 问题。

以上是关于Swift 中的外观代理/UI_APPEARANCE_SELECTOR?的主要内容,如果未能解决你的问题,请参考以下文章

Swift 中的设计模式 #3 外观模式与适配器模式

代理 适配 外观

swift设计模式学习 - 外观模式

swift设计模式学习 - 外观模式

UIBarButtonItem 外观代理设置字体属性在 iOS 11 中不起作用

如果我为标签字体使用外观代理,我无法通过 Interface Builder 设置字体大小