@IBInspectable dengan enum?

87

Saya ingin membuat @IBInspectableelemen seperti yang Anda lihat pada gambar di bawah ini:

masukkan deskripsi gambar di sini

ide saya adalah menggunakan sesuatu seperti enum sebagai tipe untuk @IBInspectable, tapi sepertinya bukan itu masalahnya, ada ide bagaimana mengimplementasikan elemen seperti ini?

EDIT:

Sepertinya @IBInspectablehanya mendukung jenis ini:

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

kekecewaan

ignotusverum
sumber
Salah satu solusinya adalah dengan meletakkan properti terhitung yang dapat diperiksa di depan nilai yang ingin Anda setel. Tentu saja, itu masih tidak akan muncul secara ajaib sebagai menu pop-up dari nilai-nilai yang disebutkan di Interface Builder; tapi setidaknya Anda bisa mendefinisikan nilai yang bisa diperiksa dan menggunakannya untuk menyetel enum.
matt
8
Di WWDC tahun ini, saya bertanya kepada teknisi Apple di lab Alat Pengembang tentang hal ini. Dia mengatakan bahwa dia setuju itu akan menjadi fitur yang hebat, tetapi saat ini tidak memungkinkan. Dia menyarankan saya mengajukan radar di bugreport.apple.com yang saya lakukan. Itu ditutup sebagai duplikat dari masalah 15505220 tetapi saya akan sangat menyarankan orang-orang yang memasukkan masalah serupa. Hal-hal ini sering kali ditangani jika cukup banyak orang yang mengeluh.
Will Clarke
1
bagaimana pertanyaan ini berbeda dari stackoverflow.com/questions/27432736/…
SwiftArchitect
Kemungkinan duplikat dari Cara membuat IBInspectable of type enum
SwiftArchitect
Dan dengan SwiftUI dan Canvas baru di Xcode 11, tampaknya ini tidak akan pernah ada di peta jalan Apple
Ben Leggiero

Jawaban:

27

Itu tidak mungkin (untuk saat ini). Anda hanya dapat menggunakan jenis yang Anda lihat di bagian Atribut Waktu Proses yang Ditentukan Pengguna .

Dari dokumen Apple :

Anda dapat melampirkan atribut IBInspectable ke properti apa pun dalam deklarasi kelas, ekstensi kelas, atau kategori untuk jenis apa pun yang didukung oleh atribut runtime yang ditentukan Interface Builder: boolean, bilangan bulat atau angka floating point, string, string yang dilokalkan, persegi panjang, titik, ukuran , color, range, dan nihil.

yusuke024
sumber
2
Ketika saya ingin menggunakan enum, saya memberikan tugas eksplisit nilai enum (= 1, = 2, dll.). Dan di handler, saya menambahkan pernyataan jika nilai dari IB bukan salah satu nilai dari enum. Mengganggu bahwa enum tidak didukung, tapi setidaknya trik ini membuatnya lebih bisa digunakan.
Zev Eisenberg
Enum adalah bilangan bulat.
Amin Negm-Awad
23

Solusi lain untuk ini adalah mengubah bagaimana properti enumerasi muncul ke pembuat antarmuka. Sebagai contoh:

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

Ini mengasumsikan enum yang disebut FontWeight. Ini bergantung pada fakta bahwa enum dan nilai integer mentahnya dapat digunakan secara bergantian di Objective-C. Setelah melakukan ini, Anda dapat menentukan bilangan bulat dalam Pembuat antarmuka untuk properti yang tidak ideal, tetapi berfungsi, dan mempertahankan sejumlah kecil keamanan tipe saat menggunakan properti yang sama secara terprogram.

Ini adalah alternatif yang lebih baik daripada mendeklarasikan properti integer terpisah karena Anda tidak perlu menulis logika tambahan untuk menangani properti integer kedua yang juga dapat digunakan untuk mencapai hal yang sama.

Namun, ini tidak berfungsi dengan Swift karena kami tidak dapat secara implisit mentransmisikan dari integer ke enum. Pikiran apa pun tentang pemecahan yang akan dihargai.

Anthony Mattox
sumber
2
Saya benar-benar berpikir ini berhasil di Swift, tetapi dalam pengujian lebih lanjut ... tidak
Dan Rosenstark
7

Saya melakukan ini menggunakan nilai Inspectable NSInteger dan menimpa penyetel untuk memungkinkannya menyetel enum. Ini memiliki batasan untuk tidak menggunakan daftar popup dan jika Anda mengubah nilai enum Anda, maka opsi antarmuka tidak akan diperbarui untuk mencocokkan.

Contoh.

Di File Header:

typedef NS_ENUM(NSInteger, LabelStyle)
{
    LabelStyleContent = 0, //Default to content label
    LabelStyleHeader,
};

...

@property LabelStyle labelStyle;
@property (nonatomic, setter=setLabelAsInt:) IBInspectable NSInteger labelStyleLink;

Dalam file implementasi:

- (void)setLabelAsInt:(NSInteger)value
{
    self.labelStyle = (LabelStyle)value;
}

Anda dapat secara opsional menambahkan beberapa logika di sana untuk memastikan bahwa itu disetel ke nilai yang valid

Matthew Cawley
sumber
Tidak yakin mengapa ini ditolak. Sepertinya cara yang baik untuk mengatasi masalah tersebut.
Fogmeister
Terima kasih @Fogmeister - Saya sebenarnya menggunakan implementasi ini di dalam aplikasi saat ini :)
Matthew Cawley
4

Sikhapol benar, enum belum didukung juga tidak di xCode 9. Saya percaya pendekatan teraman adalah dengan menggunakan enum sebagai string dan menerapkan var IBInspectable "bayangan" (pribadi). Berikut adalah contoh item BarBtnPaintCode yang merepresentasikan item barbutton yang dapat diberi gaya dengan ikon kustom (yang dilakukan menggunakan PaintCode) tepat di dalam Interface Builder (swift 4).

Dalam membangun antarmuka Anda cukup memasukkan string (identik dengan nilai enum), yang membuatnya tetap jelas (jika Anda memasukkan angka tidak ada yang tahu apa artinya)

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
        }

    }

}
HixField
sumber
Solusi fantastis, diimplementasikan dengan Swift 4 tanpa masalah. jika Anda menggunakan ini, berhati-hatilah dengan jenis ejaan dengan benar di storyboard dan xibs
MindBlower3
1

Seperti yang dijawab oleh @sikhapol, hal itu tidak mungkin. Solusi yang saya gunakan untuk ini adalah memiliki banyak IBInspectablekelemahan di kelas saya dan cukup pilih satu di pembuat antarmuka. Untuk keamanan tambahan yang beberapa tidak disetel, tambahkan NSAssertpenyetel untuk masing-masing.

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

Ini IMO sedikit membosankan dan sedikit ceroboh, tapi itu satu-satunya cara untuk mencapai perilaku seperti ini yang dapat saya pikirkan.

Chris
sumber
1

Saya ingin menambahkan bahwa pengenal an enumtidak tersedia pada waktu proses untuk siapa pun di Objective-C. Jadi tidak mungkin untuk menampilkannya dimanapun.

Amin Negm-Awad
sumber
1

Solusi saya adalah melakukan:

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

Di IB itu sendiri, Anda perlu menyetel int di bidang keyboardType

Gal Marom
sumber