@IBInspectable với enum?


86

Tôi muốn tạo @IBInspectablephần tử như bạn thấy ở hình bên dưới:

nhập mô tả hình ảnh ở đây

ý tưởng của tôi là sử dụng một cái gì đó như enum làm kiểu cho @IBInspectable, nhưng có vẻ như không phải vậy, bất kỳ ý tưởng nào về cách triển khai phần tử như thế này?

BIÊN TẬP:

Có vẻ như @IBInspectablechỉ hỗ trợ các loại sau:

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

bummer


Một giải pháp khác, là đặt một thuộc tính tính toán có thể kiểm tra trước giá trị bạn muốn đặt. Tất nhiên, nó vẫn sẽ không xuất hiện một cách kỳ diệu dưới dạng menu bật lên gồm các giá trị được liệt kê trong Trình tạo giao diện; nhưng ít nhất bạn có thể xác định một giá trị có thể kiểm tra và sử dụng nó để đặt một enum.
matt

8
Tại WWDC năm nay, tôi đã hỏi một kỹ sư của Apple trong phòng thí nghiệm Công cụ dành cho nhà phát triển về điều này. Anh ấy nói rằng anh ấy đồng ý rằng đây sẽ là một tính năng tuyệt vời, nhưng hiện tại thì chưa thể. Anh ấy đề nghị tôi gửi một radar tại bugreport.apple.com mà tôi đã làm. Nó đã bị đóng lại vì một bản sao của số phát hành 15505220 nhưng tôi thực sự khuyên mọi người nên đặt những vấn đề tương tự. Những điều này thường được giải quyết nếu có đủ người phàn nàn.
Sẽ Clarke vào

1
như thế nào là câu hỏi này khác với stackoverflow.com/questions/27432736/...
SwiftArchitect


Và với SwiftUI và Canvas mới trong Xcode 11, có vẻ như điều này sẽ không bao giờ có trên lộ trình của Apple
Bến Leggiero

Câu trả lời:


26

Điều đó là không thể (hiện tại). Bạn chỉ có thể sử dụng những loại mà bạn thấy trong phần Thuộc tính thời gian chạy do người dùng xác định .

Từ tài liệu của Apple :

Bạn có thể đính kèm thuộc tính IBInspectable vào bất kỳ thuộc tính nào trong khai báo lớp, phần mở rộng lớp hoặc danh mục cho bất kỳ loại nào được hỗ trợ bởi các thuộc tính thời gian chạy do Bộ tạo giao diện xác định: boolean, số nguyên hoặc số dấu chấm động, chuỗi, chuỗi bản địa hóa, hình chữ nhật, điểm, kích thước , màu sắc, phạm vi và số không.


2
Khi tôi muốn sử dụng một enum, tôi gán các giá trị enum một cách rõ ràng (= 1, = 2, v.v.). Và trong trình xử lý, tôi thêm một khẳng định nếu giá trị từ IB không phải là một trong những giá trị từ enum. Thật khó chịu khi enums không được hỗ trợ, nhưng ít nhất thủ thuật này khiến chúng trở nên hữu dụng hơn.
Zev Eisenberg

Một enum là một số nguyên.
Amin Negm-Awad

23

Một giải pháp khác cho việc này là thay đổi cách một thuộc tính liệt kê xuất hiện cho trình tạo giao diện. Ví dụ:

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

Điều này giả định một enum được gọi là FontWeight. Nó dựa trên thực tế rằng enum và các giá trị nguyên thô của chúng có thể được sử dụng thay thế cho nhau trong Objective-C. Sau khi thực hiện việc này, bạn có thể chỉ định một số nguyên trong Trình tạo giao diện cho thuộc tính không phải là lý tưởng, nhưng hoạt động và giữ lại một lượng nhỏ an toàn kiểu khi sử dụng cùng một thuộc tính theo chương trình.

Đây là một giải pháp thay thế tốt hơn so với việc khai báo một thuộc tính số nguyên riêng biệt vì bạn không cần phải viết thêm logic để xử lý thuộc tính số nguyên thứ hai cũng có thể được sử dụng để thực hiện điều tương tự.

Tuy nhiên, điều này không hoạt động với Swift vì chúng tôi không thể truyền ngầm từ một số nguyên sang một enum. Bất kỳ suy nghĩ về việc giải quyết đó sẽ được đánh giá cao.


2
Tôi thực sự nghĩ này đã làm việc trong Swift, nhưng trong thử nghiệm thêm nữa ... không
Dan Rosenstark

7

Tôi thực hiện việc này bằng cách sử dụng giá trị NSInteger có thể kiểm tra và ghi đè bộ thiết lập để cho phép nó thiết lập enum. Điều này có hạn chế là không sử dụng danh sách bật lên và nếu bạn thay đổi giá trị enum của mình, thì các tùy chọn giao diện sẽ không cập nhật để phù hợp.

Thí dụ.

Trong Tệp Tiêu đề:

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

...

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

Trong tệp triển khai:

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

Bạn có thể tùy ý thêm một số logic vào đó để đảm bảo rằng nó đang được đặt thành giá trị hợp lệ


Không chắc tại sao điều này lại bị bỏ phiếu. Có vẻ như là một cách tốt để giải quyết vấn đề.
Fogmeister

Cảm ơn bạn @Fogmeister - Tôi thực sự sử dụng thực hiện này bên trong một ứng dụng vào lúc này :)
Matthew Cawley

4

Sikhapol là chính xác, enums chưa được hỗ trợ cũng không có trong xCode 9. Tôi tin rằng cách tiếp cận an toàn nhất là sử dụng enums làm chuỗi và thực hiện một IBInspectable var "bóng" (riêng tư). Đây là một ví dụ về mục BarBtnPaintCode đại diện cho một mục nút có thể được tạo kiểu bằng một biểu tượng tùy chỉnh (được thực hiện bằng PaintCode) ngay bên trong Trình tạo giao diện (swift 4).

Trong xây dựng giao diện, bạn chỉ cần nhập chuỗi (giống với giá trị enum), điều này giữ cho nó rõ ràng (nếu bạn đang nhập số không ai biết chúng có nghĩa là gì)

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
        }

    }

}

Giải pháp tuyệt vời, được triển khai với Swift 4 không có vấn đề gì. nếu bạn sử dụng này cẩn thận các loại chính tả một cách chính xác trong cốt truyện và xibs
MindBlower3

1

Như @sikhapol đã trả lời, điều này là không thể. Cách giải quyết mà tôi sử dụng cho việc này là có một loạt các IBInspectablebools trong lớp của mình và chỉ cần chọn một trong trình tạo giao diện. Để tăng cường bảo mật mà nhiều cái không được đặt, hãy thêm một bộ cài đặt NSAssertcho mỗi cái.

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

IMO này hơi tẻ nhạt và hơi cẩu thả, nhưng đó là cách duy nhất để thực hiện loại hành vi này mà tôi có thể nghĩ ra


1

Tôi muốn nói thêm rằng các số nhận dạng của an enumkhông có sẵn trong thời gian chạy cho bất kỳ ai trong Objective-C. Vì vậy, không thể có khả năng hiển thị nó ở bất cứ đâu.


1

Giải pháp của tôi là làm:

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

Trên chính IB, bạn sẽ cần đặt một số nguyên trong trường keyboardType

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.