Chciałbym stworzyć @IBInspectable
element jak na poniższym obrazku:
moim pomysłem jest użycie czegoś takiego jak wyliczenie jako typ dla @IBInspectable
, ale wygląda na to, że tak nie jest, jakieś pomysły, jak zaimplementować taki element?
EDYTOWAĆ:
Wygląda na to, że @IBInspectable
obsługuje tylko te typy:
Int
CGFloat
Double
String
Bool
CGPoint
CGSize
CGRect
UIColor
UIImage
porażka
Odpowiedzi:
To nie jest możliwe (na razie). Możesz używać tylko tych typów, które widzisz w sekcji Atrybuty środowiska wykonawczego zdefiniowane przez użytkownika .
Z dokumentu Apple :
źródło
Innym obejściem tego problemu jest zmiana wyglądu właściwości wyliczenia w konstruktorze interfejsu. Na przykład:
#if TARGET_INTERFACE_BUILDER @property (nonatomic, assign) IBInspectable NSInteger fontWeight; #else @property (nonatomic, assign) FontWeight fontWeight; #endif
Zakłada się wyliczenie o nazwie FontWeight. Opiera się na fakcie, że wyliczenia i ich surowe wartości całkowite mogą być używane nieco zamiennie w Objective-C. Po wykonaniu tej czynności możesz określić liczbę całkowitą w narzędziu do tworzenia interfejsu dla właściwości, która nie jest idealna, ale działa i zachowuje niewielki poziom bezpieczeństwa typów, gdy używasz tej samej właściwości programowo.
Jest to lepsza alternatywa niż deklarowanie oddzielnej właściwości całkowitej, ponieważ nie musisz pisać dodatkowej logiki do obsługi drugiej właściwości całkowitej, która mogłaby być również użyta do osiągnięcia tego samego.
Jednak to nie działa w Swift, ponieważ nie jesteśmy w stanie niejawnie rzutować z liczby całkowitej na wyliczenie. Wszelkie przemyślenia na temat rozwiązania tego będą mile widziane.
źródło
Robię to przy użyciu wartości Inspectable NSInteger i zastępuję metodę ustawiającą, aby umożliwić ustawienie wyliczenia. Ma to ograniczenie polegające na nieużywaniu listy podręcznej i jeśli zmienisz wartości wyliczenia, opcje interfejsu nie zostaną zaktualizowane, aby pasowały.
Przykład.
W pliku nagłówkowym:
typedef NS_ENUM(NSInteger, LabelStyle) { LabelStyleContent = 0, //Default to content label LabelStyleHeader, }; ... @property LabelStyle labelStyle; @property (nonatomic, setter=setLabelAsInt:) IBInspectable NSInteger labelStyleLink;
W pliku wdrożeniowym:
- (void)setLabelAsInt:(NSInteger)value { self.labelStyle = (LabelStyle)value; }
Możesz opcjonalnie dodać tam logikę, aby upewnić się, że jest ustawiona na prawidłową wartość
źródło
Sikhapol jest poprawny, wyliczenia nie są jeszcze obsługiwane, również nie w xCode 9. Uważam, że najbezpieczniejszym podejściem jest użycie wyliczeń jako ciągów znaków i zaimplementowanie "shadow" (prywatnej) zmiennej IBInspectable. Oto przykład elementu BarBtnPaintCode, który reprezentuje element barbutton, który można stylizować za pomocą niestandardowej ikony (wykonanej za pomocą PaintCode) bezpośrednio w Interface Builder (swift 4).
W budowaniu interfejsu po prostu wpisujesz ciąg (identyczny z wartością wyliczenia), dzięki czemu jest jasne (jeśli wpisujesz liczby, nikt nie wie, co oznaczają)
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 } } }
źródło
Jak odpowiedział @sikhapol, nie jest to możliwe. Obejściem, którego używam w tym celu, jest posiadanie kilku
IBInspectable
booli w mojej klasie i po prostu wybranie jednego w konstruktorze interfejsu. Dla dodatkowego bezpieczeństwa, że nie ustawiono wielu z nich, dodajNSAssert
setter dla każdego z nich.- (void)setSomeBool:(BOOL)flag { if (flag) { NSAssert(!_someOtherFlag && !_someThirdFlag, @"Only one flag can be set"); } }
To trochę żmudne i trochę niechlujne IMO, ale to jedyny sposób na osiągnięcie tego rodzaju zachowania, o którym przychodzi mi do głowy
źródło
Chcę dodać, że identyfikatory
enum
nie są dostępne w czasie wykonywania dla nikogo w Objective-C. Nie ma więc możliwości nigdzie go wyświetlać.źródło
Moim rozwiązaniem było:
@IBInspectable var keyboardType = UIKeyboardType.default.rawValue { didSet { textField.keyboardType = UIKeyboardType(rawValue: keyboardType)! } }
W samym IB będziesz musiał ustawić int w polu keyboardType
źródło