@IBInspectable与枚举类型?

92

我想创建类似下图中所示的@IBInspectable元素:

enter image description here

我的想法是将枚举作为@IBInspectable的类型,但似乎行不通,有什么实现此类元素的方法吗?

编辑:

看起来@IBInspectable只支持以下这些类型:

  • Int
  • CGFloat
  • Double
  • String
  • Bool
  • CGPoint
  • CGSize
  • CGRect
  • UIColor
  • UIImage

遗憾。


一种解决方法是在要设置的值前面放置一个可检查的计算属性。当然,它仍然不会像在Interface Builder中枚举值的弹出菜单那样神奇地出现;但至少您可以定义一个可检查的值并用它来设置枚举。 - matt
9
今年的 WWDC,我在开发工具实验室询问了一位苹果工程师。他表示同意这将是一个很棒的功能,但目前还不可能。他建议我在 https://bugreport.apple.com 上提交一份问题报告,我也照做了。该报告被关闭,并列入了15505220问题的重复报告,但我强烈建议其他人也提出类似的问题。如果有足够多的人抱怨,这些问题通常会得到解决。 - William Key
1
这个问题与https://dev59.com/-F4c5IYBdhLWcg3w3tgu有何不同? - SwiftArchitect
可能是如何创建一个类型为枚举的IBInspectable的重复问题。 - SwiftArchitect
而且随着SwiftUI和Xcode 11中的新画布,似乎这将永远不会出现在苹果的路线图上。 - Ky -
7个回答

27

目前不可能做到这一点。您只能使用在 用户自定义运行时属性 部分中看到的这些类型。

根据苹果公司的 文档

您可以将 IBInspectable 属性附加到类声明、类扩展或类别中的任何属性上,针对接口构建器定义的运行时属性支持的任何类型:布尔值、整数或浮点数、字符串、本地化字符串、矩形、点、大小、颜色、范围和 nil。


2
当我想使用枚举时,我会给枚举值明确的赋值(= 1,= 2等)。在处理程序中,如果来自IB的值不是枚举值之一,我会添加一个断言。很烦人的是,枚举不受支持,但这个技巧使它们更易用。 - Zev Eisenberg
枚举是一个整数。 - Amin Negm-Awad

24

另一个应对方法是更改枚举属性在界面构建器中的显示方式。例如:

#if TARGET_INTERFACE_BUILDER
@property (nonatomic, assign) IBInspectable NSInteger fontWeight;
#else
@property (nonatomic, assign) FontWeight fontWeight;
#endif

假设有一个名为“FontWeight”的枚举,此方法依赖于 Objective-C 中的枚举及其原始整数值可以在某种程度上互换使用的事实。完成此操作后,您可以在界面生成器中为属性指定整数,尽管这不是理想的,但它仍然有效,并在以编程方式使用相同属性时保留了一小部分类型安全性。

与声明单独的整数属性相比,这是更好的选择,因为您不需要编写额外的逻辑来处理第二个整数属性,该属性也可以用于完成相同的事情。

但是,在Swift中,这种方法无法工作,因为我们无法将整数隐式转换为枚举类型。如果有任何解决方法,请告知。


4
我本以为这个在Swift中可以工作,但在进一步测试后……不行。 - Dan Rosenstark

7

我使用一个可检查的NSInteger值并重写setter方法来允许设置枚举。这种方法的限制是不能使用弹出列表,如果你更改了枚举值,那么界面选项将不会更新以匹配。

示例:

在头文件中:

typedef NS_ENUM(NSInteger, LabelStyle)
{
    LabelStyleContent = 0, //Default to content label
    LabelStyleHeader,
};

...

@property LabelStyle labelStyle;
@property (nonatomic, setter=setLabelAsInt:) IBInspectable NSInteger labelStyleLink;

在实现文件中:
- (void)setLabelAsInt:(NSInteger)value
{
    self.labelStyle = (LabelStyle)value;
}

你可以选择在其中添加一些逻辑,以确保它被设置为有效值。


不确定为什么这被投票否决了。看起来这是解决问题的好方法。 - Fogmeister
谢谢@Fogmeister - 我目前正在一个应用程序中使用这个实现 :) - Matthew Cawley

4
Sikhapol说得对,枚举类型目前还不支持在xCode 9中使用。为了保险起见,建议将枚举类型实现为字符串,并添加一个“影子”(私有)IBInspectable 变量。以下是一个BarBtnPaintCode项目的示例,该项目表示可以使用自定义图标(使用PaintCode完成)样式化的barbutton项,可直接在Interface Builder (swift 4)中进行设置。
在界面构建器中,只需输入与枚举值相同的字符串即可,这样做也更加清晰易懂(如果输入数字,则没有人知道它们的含义)。
class BarBtnPaintCode: BarBtnPaintCodeBase {

    enum TypeOfButton: String {
        case cancel
        case ok
        case done
        case edit
        case scanQr
        //values used for tracking if wrong input is used
        case uninitializedLoadedFromStoryboard
        case unknown
    }

    var typeOfButton = TypeOfButton.uninitializedLoadedFromStoryboard

    @IBInspectable private var type : String {
        set {
            typeOfButton = TypeOfButton(rawValue: newValue) ?? .unknown
            setup()
        }
        get {
            return typeOfButton.rawValue
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    init(typeOfButton: TypeOfButton, title: String? = nil, target: AnyObject?, action: Selector) {
        super.init()
        self.typeOfButton = typeOfButton
        setup()
        self.target = target
        self.action = action
        self.title  = title
    }

    override func setup() {
        //same for all
        setTitleTextAttributes([NSAttributedStringKey.font : UIFont.defaultFont(size: 15)],for: UIControlState.normal)
        //depending on the type
        switch typeOfButton {
        case .cancel  :
            title = nil
            image = PaintCode.imageOfBarbtn_cancel(language: currentVisibleLanguage)
        case .ok      :
            title = nil
            image = PaintCode.imageOfBarbtn_ok(language: currentVisibleLanguage)
        case .done    :
            title = nil
            image = PaintCode.imageOfBarbtn_done(language: currentVisibleLanguage)
        case .edit    :
            title = nil
            image = PaintCode.imageOfBarbtn_edit(language: currentVisibleLanguage)
        case .uninitializedLoadedFromStoryboard :
            title = nil
            image = PaintCode.imageOfBarbtn_unknown
            break
        case .unknown:
            log.error("BarBtnPaintCode used with unrecognized type")
            title = nil
            image = PaintCode.imageOfBarbtn_unknown
            break
        }

    }

}

神奇的解决方案,使用Swift 4实现没有问题。 如果您使用此解决方案,请注意在storyboards和xibs中正确拼写类型。 - MindBlower3

1
我的解决方案是:做:

@IBInspectable  
var keyboardType = UIKeyboardType.default.rawValue {
        didSet { 
             textField.keyboardType = UIKeyboardType(rawValue: keyboardType)! 
        }
}

在IB中,您需要在keyboardType字段中设置一个int。

1

我想补充一点,在Objective-C中,enum的标识符对于任何人在运行时都不可用。因此无法在任何地方显示它。


1
正如@sikhapol所回答的那样,这是不可能的。我在类中使用一堆IBInspectable布尔值来解决这个问题,在接口构建器中只需选择其中一个即可。为了确保没有设置多个,可以在每个属性的setter中添加NSAssert
- (void)setSomeBool:(BOOL)flag
{
    if (flag)
    {
        NSAssert(!_someOtherFlag && !_someThirdFlag, @"Only one flag can be set");
    }
}

这有点繁琐且有些不太规范,但这是我能想到的实现这种行为的唯一方法。

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