外观代理 / Swift中的UI_APPEARANCE_SELECTOR是什么?

50

苹果文档说明:

要参与外观代理 API,请在标头中标记具有 UI_APPEARANCE_SELECTOR 的外观属性选择器。

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

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

我该如何在Swift中实现同样的功能?

4个回答

51

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

例如:

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

然后:

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

我需要试一下。有没有文档记录? - Mazyod
据我所知,这并没有记录在案,但我尝试过了,它起作用了。基本上,从Objective-C框架动态访问的Swift属性应该标记为dynamic。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。 - Yoichi Tagaya
很遗憾,在Xcode 8.3.2 iOS 9.1中,它无法与UIBarButton子类一起使用,并在我设置外观并实例化新的Custom UIBarButtonSubclass后导致了UIKit崩溃。 - Nikolay Shubenkov
还需要在属性上添加@objc属性才能使其正常工作。 - maxkonovalov

3

我没有找到解决方案,但是找到了一个变通方法。我将属性设置为类变量,而不是进行注释。

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) 

我希望它能够帮助到某些人!


1
在Swift中,您不需要(实际上,您不能)使用UI_APPEARANCE_SELECTOR注释属性。
只需确保您的外观属性访问器方法符合以下形式:
func propertyForAxis1(axis1: IntegerType, axis2: IntegerType, axisN: IntegerType) -> PropertyType
func setProperty(property: PropertyType, forAxis1 axis1: IntegerType, axis2: IntegerType)

Source: Apple Documentation

例如:

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

然后,您可以像这样设置外观属性:
MyView.appearance().setStarViewColor(someColor)

我目前在我的Swift项目中使用这个解决方案,它有效,希望对您也有所帮助。


你好,请问你能否发布一下你正在使用的类?我似乎无法正确调用我的setter,每次尝试调用时都会出现“BAD_ACCESS”错误。我在想是否我声明类的方式不正确,它是UIButton的子类,并且我遵循文档中所说的UIAppearanceContainer协议!谢谢! - Rich
@Rich 请查看我的gist,包括整个类,希望能有所帮助。 - guojiubo
不幸的是,这并不允许我更改特定实例的颜色。有任何想法如何实现吗?谢谢! - Reinhold
2
很遗憾,回复晚了,但我发现将方法标记为动态的可以解决UIButton的BAD_ACCESS问题。 - Keab42

1

根据之前的回答,这是我实现的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)
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接