web-dev-qa-db-fra.com

@IB Inspectable avec enum?

Je voudrais créer @IBInspectable élément comme vous le voyez sur l'image ci-dessous:

enter image description here

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

77
ignotusverum

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.

25
yusuke024

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.

21
Anthony Mattox

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

7
Matthew Cawley

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
        }

    }

}
1
HixField

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ù.

1
Amin Negm-Awad

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.

1
Chris

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

1
Gal Marom