@IBІнспективно з переліченням?


86

Я хотів би створити @IBInspectableелемент, як ви бачите на малюнку нижче:

введіть тут опис зображення

моя ідея полягає у використанні чогось типу enum як типу @IBInspectable, але схоже, це не так, будь-які ідеї, як реалізувати такий елемент?

РЕДАГУВАТИ:

Схоже, @IBInspectableпідтримуються лише такі типи:

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

облом


Рішальним шляхом, свого роду, є розміщення обстежуваної властивості, що перевіряється, перед значенням, яке потрібно встановити. Звичайно, це все одно чарівно не відображатиметься як спливаюче меню з перерахованими значеннями у Interface Builder; але принаймні ви можете визначити перевіряється значення та використовувати його для встановлення переліку.
matt

8
Цього року на WWDC я запитав про це інженера Apple у лабораторії Developer Tools. Він сказав, що погодився, що це буде чудова функція, але наразі це неможливо. Він запропонував мені подати радар на bugreport.apple.com, що я і зробив. Він був закритий як копія випуску 15505220, але я настійно рекомендую людям розміщувати подібні випуски. До цих речей часто звертаються, якщо достатня кількість людей скаржиться.
Уілл Кларк

1
як це питання відрізняється від stackoverflow.com/questions/27432736 / ...
SwiftArchitect


А з SwiftUI та новим Canvas у Xcode 11, схоже, цього ніколи не буде на дорожній карті Apple
Бен Леггієро,

Відповіді:


26

Це неможливо (наразі). Ви можете використовувати лише ті типи, які ви бачите в розділі Визначені користувачем атрибути виконання .

Від компанії Apple документа :

Ви можете приєднати атрибут IBInspectable до будь-якої властивості в декларації класу, розширенні класу або категорії для будь-якого типу, який підтримується визначеними конструктором інтерфейсу атрибутами середовища виконання: логічним, цілим чи числом із плаваючою комою, рядком, локалізованим рядком, прямокутником, точкою, розміром , колір, діапазон та нуль.


2
Коли я хочу використовувати перерахування, я даю значенням перерахування явні призначення (= 1, = 2 тощо). І в обробнику я додаю твердження, якщо значення з IB не є одним із значень з переліку. Прикро, що перелічення не підтримуються, але цей трюк робить їх принаймні придатними, принаймні.
Зев Айзенберг

Перелік - це ціле число.
Амін Негм-Авад

23

Іншим вирішенням цього є зміна того, як властивість перерахування здається інтерфейсу конструктора. Наприклад:

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

Це передбачає перерахування під назвою FontWeight. Він покладається на той факт, що перелічення та їх цілі цілі цілі значення можуть бути дещо взаємозамінні в Objective-C. Після цього ви зможете вказати ціле число у конструкторі інтерфейсів для властивості, яка не є ідеальною, але працює, і зберігає невелику кількість захисту типу при програмному використанні тієї ж властивості.

Це краща альтернатива, ніж оголошення окремої цілочисельної властивості, оскільки вам не потрібно писати додаткову логіку для обробки другої цілочисельної властивості, яка також може бути використана для виконання того самого.

Однак це не працює з Swift, оскільки ми не можемо неявно передати з цілого числа на перерахування. Будь-які думки щодо вирішення, які були б вдячні.


2
Я справді думав, що це спрацювало в Свіфті, але при подальшому тестуванні ... ні
Ден Розенстарк

7

Я роблю це, використовуючи значення Inspectable NSInteger, і перевизначаю сеттер, щоб дозволити йому встановити перелік. Це має обмеження невикористання спливаючого списку, і якщо ви зміните значення перерахування, параметри інтерфейсу не оновляться, щоб відповідати.

Приклад.

У файлі заголовка:

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 - На даний момент я фактично використовую цю реалізацію в додатку :)
Matthew Cawley

4

Сихаполь правильний, перерахування ще не підтримуються, також не в xCode 9. Я вважаю, що найбезпечнішим підходом є використання перерахувань як рядків та реалізація "тіньового" (приватного) IBInspectable var. Ось приклад елемента BarBtnPaintCode, який представляє елемент барбутона, який можна стилізувати за допомогою власної піктограми (що робиться за допомогою PaintCode) прямо в 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 без проблем. якщо ви використовуєте це, будьте обережні з правильним написанням типів в раскадровках та xibs
MindBlower3

1

Як відповів @sikhapol, це неможливо. Обхідний шлях, який я використовую для цього, полягає в тому, щоб мати IBInspectableу своєму класі купу булів і просто вибрати один у конструкторі інтерфейсів. Для додаткової безпеки, якщо не встановлено декілька, додайте NSAssertв налаштування для кожного з них.

- (void)setSomeBool:(BOOL)flag
{
    if (flag)
    {
        NSAssert(!_someOtherFlag && !_someThirdFlag, @"Only one flag can be set");
    }
}

Це трохи нудне і трохи неакуратне IMO, але це єдиний спосіб здійснити таку поведінку, про яку я можу подумати


1

Я хочу додати, що ідентифікатори an enumнедоступні під час виконання ні для кого в Objective-C. Отже, не може бути можливості його десь відображати.


1

Моє рішення було зробити:

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

На самому IB вам потрібно буде встановити int у полі keyboardType

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.