@IBInspectable with enum?
I'd like to create @IBInspectable
element as you see at the picture below :
my idea is to use something like enum as type for @IBInspectable
, but it looks like it's not the case, any ideas how to implement element like this ?
EDIT:
It looks like @IBInspectable
supports only these types :
Int
CGFloat
Double
String
Bool
CGPoint
CGSize
CGRect
UIColor
UIImage
bummer
Solution 1:
That's not possible (for now). You can only use those types that you see in User Defined Runtime Attributes section.
From Apple's doc:
You can attach the IBInspectable attribute to any property in a class declaration, class extension, or category for any type that’s supported by the Interface Builder defined runtime attributes: boolean, integer or floating point number, string, localized string, rectangle, point, size, color, range, and nil.
Solution 2:
Another work-around for this is to alter how an enumeration property appears to interface builder. For example:
#if TARGET_INTERFACE_BUILDER
@property (nonatomic, assign) IBInspectable NSInteger fontWeight;
#else
@property (nonatomic, assign) FontWeight fontWeight;
#endif
This assumes an enum called FontWeight. It relies on the fact that enums and their raw integer values can be used somewhat interchangeably in Objective-C. After doing this you are able to specify an integer in Interface builder for the property which is not ideal, but works, and retains a small amount of type safety when using the same property programatically.
This is a better alternative than declaring a separate integer property because you don't need to write extra logic to handle a second integer property which could also be used to accomplish the same thing.
However, this does not work with Swift because we're not able to implicitly cast from an integer to an enum. Any thoughts on solving that would be appreciated.
Solution 3:
I do this using a Inspectable NSInteger value and override the setter to allow it to set the enum. This has the limitation of not using a popup list and if you change your enum values, then the interface options will not update to match.
Example.
In Header File:
typedef NS_ENUM(NSInteger, LabelStyle)
{
LabelStyleContent = 0, //Default to content label
LabelStyleHeader,
};
...
@property LabelStyle labelStyle;
@property (nonatomic, setter=setLabelAsInt:) IBInspectable NSInteger labelStyleLink;
In the implementation file:
- (void)setLabelAsInt:(NSInteger)value
{
self.labelStyle = (LabelStyle)value;
}
You could optionally add some logic in there to ensure that it is being set to a valid value
Solution 4:
Sikhapol is correct, enums are not yet supported also not in xCode 9. I believe the safest approach is to use enums as strings and implement a "shadow" (private) IBInspectable var. Here is an example of a BarBtnPaintCode item which represents a barbutton item that can be styled with a custom icon (that is done using PaintCode) right inside Interface Builder (swift 4).
In interface build you just enter the string (identical to the enum value), which keeps it clear (if you are entering numbers nobody knows what they mean)
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
}
}
}