Je voudrais créer @IBInspectable
élément comme vous le voyez sur l'image ci-dessous:
mon idée est d'utiliser quelque chose comme enum comme type pour @IBInspectable
_, mais on dirait que ce n’est pas le cas, des idées pour mettre en œuvre un tel élément?
MODIFIER:
Ça ressemble à @IBInspectable
ne supporte que ces types:
Int
CGFloat
Double
String
Bool
CGPoint
CGSize
CGRect
UIColor
UIImage
bummer
Ce n'est pas possible (pour l'instant). Vous ne pouvez utiliser que les types que vous voyez dans la section Attributs d'exécution définis par l'utilisateur .
De la part d'Apple doc :
Vous pouvez attacher l'attribut IBInspectable à n'importe quelle propriété d'une déclaration de classe, d'une extension de classe ou d'une catégorie pour tout type pris en charge par les attributs d'exécution définis par Interface Builder: booléen, nombre entier ou nombre à virgule flottante, chaîne, chaîne localisée, rectangle, point, taille , couleur, gamme et zéro.
Une autre solution consiste à modifier l'apparence d'une propriété d'énumération pour le générateur d'interface. Par exemple:
#if TARGET_INTERFACE_BUILDER
@property (nonatomic, assign) IBInspectable NSInteger fontWeight;
#else
@property (nonatomic, assign) FontWeight fontWeight;
#endif
Cela suppose une énumération appelée FontWeight. Il repose sur le fait que les énumérations et leurs valeurs entières brutes peuvent être utilisées de manière interchangeable dans Objective-C. Cela fait, vous pouvez spécifier un entier dans le générateur Interface pour la propriété, ce qui n'est pas idéal, mais fonctionne et conserve une petite quantité de sécurité lorsque vous utilisez la même propriété par programme.
C'est une meilleure alternative que de déclarer une propriété entière distincte car il n'est pas nécessaire d'écrire de la logique supplémentaire pour gérer une deuxième propriété entière qui pourrait également être utilisée pour accomplir la même chose.
Cependant, cela ne fonctionne pas avec Swift car nous ne sommes pas en mesure de convertir implicitement un entier en un enum. Toute idée de résolution qui en résulterait serait appréciée.
Je fais cela en utilisant une valeur Inspectable NSInteger et remplace le setter pour lui permettre de définir l’énumération. Cela a la limite de ne pas utiliser de liste contextuelle et si vous modifiez vos valeurs enum, les options d'interface ne seront pas mises à jour pour correspondre.
Exemple.
Dans le fichier d'en-tête:
typedef NS_ENUM(NSInteger, LabelStyle)
{
LabelStyleContent = 0, //Default to content label
LabelStyleHeader,
};
...
@property LabelStyle labelStyle;
@property (nonatomic, setter=setLabelAsInt:) IBInspectable NSInteger labelStyleLink;
Dans le fichier d'implémentation:
- (void)setLabelAsInt:(NSInteger)value
{
self.labelStyle = (LabelStyle)value;
}
Vous pouvez éventuellement ajouter une logique pour vous assurer qu'il est défini sur une valeur valide
Sikhapol a raison, les énumérations ne sont pas encore prises en charge, pas plus que dans xCode 9. Je pense que l’approche la plus sûre consiste à utiliser des énumérations comme des chaînes et à mettre en œuvre une variable "shadow" (privée) IBInspectable. Voici un exemple d'élément BarBtnPaintCode qui représente un élément de bouton à barres pouvant être stylé avec une icône personnalisée (réalisée à l'aide de PaintCode) directement dans Interface Builder (Swift 4).
Dans Interface Build, vous entrez simplement la chaîne (identique à la valeur enum), ce qui la rend claire (si vous entrez des nombres, personne ne sait ce qu'ils signifient)
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
}
}
}
Je veux ajouter que les identifiants d'un enum
ne sont pas disponibles au moment de l'exécution pour quiconque en Objective-C. Il ne peut donc pas être possible de l'afficher n'importe où.
Comme @sikhapol a répondu, ce n'est pas possible. La solution de contournement que j’utilise pour cela est d’avoir un groupe de IBInspectable
bools dans ma classe et d’en sélectionner un dans le générateur d’interface. Pour plus de sécurité en évitant de définir plusieurs unités, ajoutez un NSAssert
dans le sélecteur pour chacune d'entre elles.
- (void)setSomeBool:(BOOL)flag
{
if (flag)
{
NSAssert(!_someOtherFlag && !_someThirdFlag, @"Only one flag can be set");
}
}
C'est un peu fastidieux et un peu bâclé, mais c'est le seul moyen d'obtenir ce genre de comportement auquel je peux penser.
Ma solution était de faire:
@IBInspectable
var keyboardType = UIKeyboardType.default.rawValue {
didSet {
textField.keyboardType = UIKeyboardType(rawValue: keyboardType)!
}
}
Sur l'IB lui-même, vous devrez définir un int dans le champ keyboardType