If you've ever wished you could use a third-party framework in XCode's interface builder, you'll be glad to know there's a workaround for enabling some of this functionality. Sometimes it's much easier to do all of the layout and positioning in storyboards using constraints and autolayout. Since Xcode 6 and iOS 8, Apple has allowed custom classes to use IBDesignable to render the control in the interface builder and IBInspectable to allow you to configure properties in the Attributes Inspector. For the most part, though, third-party libraries lack this functionality, since static iOS frameworks don't have the ability to use IBDesignable and IBInspectable. Sure, you can create a view and set the custom class via the identity inspector, but you're essentially stuck with a blank view in the designer that you'll have to fully configure in code. There is a workaround for this though, and a mechanism to add in some of the interface builder functionality that third party frameworks often lack.
Building Frameworks for the Interface Builder
Recently, I've been working through both creating a custom checkbox control and using it to create a framework. One takeaway from the process has been how poorly most frameworks seem to work with IBDesignable and IBInspectable. If you're not familiar with either designation, IBDesignable views render in the interface builder, and IBInspectable properties are configurable in the interface builder. Many frameworks don't try to implement these features, since they're only supported in the newest versions of iOS 8+. I've tried implementing these properties into my own frameworks, and it's a mixed bag in terms of Xcode 7 functionality. While IBInspectable sometimes works without issue, IBDesignable never seemed to function correctly. In my search for a resolution to this problem, I stumbled across several different articles variously stating that using these properties in your frameworks are not fully supported at this point. I was disappointed by this, but I stumbled upon a kind of hack/workaround that I found interesting, and that often seems to allow frameworks to be used in the designer.
Subclassing the Controls in Frameworks
To get around these issues, I was able to import the framework into my project, and then create my own class which subclasses the control that I wanted to use in the designer. Once I'd created this class I could go ahead and use IBDesignable and declare the same properties from the superclass but mark them with IBInspectable in the header of my subclass. Using this mechanism, I was able to use the checkbox control that I'd encapsulated into a static framework in the interface builder. I could also mark properties from the superclass IBInspectable here and they showed up in the designer. While it's definitely a bit of a hack, I was happy to see that I could force this functionality if I really needed it.
#import <UIKit/UIKit.h> #import <CheckboxKit/Checkbox.h> IB_DESIGNABLE @interface MyCheckbox : Checkbox @property IBInspectable UIColor *checkColor; @property IBInspectable UIColor *boxFillColor; @property IBInspectable UIColor *boxBorderColor; @property IBInspectable UIFont *labelFont; @property IBInspectable UIColor *labelTextColor; @property IBInspectable BOOL isEnabled; @property IBInspectable BOOL isChecked; @property IBInspectable BOOL showTextLabel; @property IBInspectable (nonatomic, strong) NSString *text; @end
Trying to Subclass a XuniRadialGauge
I wanted to take the process a little further and do something similar with one of our Xuni controls. For a number of compatibility reasons, Xuni is implemented as a static framework, so I figured I'd be able to do something similar if I really wanted to use one of the controls in the interface builder. Testing this on one of the gauge controls made the most sense, since they only have a handful of properties. I followed the same process: I created my own MyRadialGauge cocoa class as a subclass of XuniRadialGauge. I declared a handful of properties IBInspectable so that I could configure them in the Interface builder and marked the class as IBInspectable. The process worked: I was able to use the controls in the interface builder.
#import <Foundation/Foundation.h> #import <XuniGaugeKit/XuniGaugeKit.h> IB_DESIGNABLE @interface MyRadialGauge : XuniRadialGauge @property (nonatomic) IBInspectable double min; @property (nonatomic) IBInspectable double max; @property (nonatomic) IBInspectable double value; @property (nonatomic) IBInspectable UIColor *pointerColor; @property (nonatomic) IBInspectable double startAngle; @property (nonatomic) IBInspectable double sweepAngle; @property (nonatomic) IBInspectable BOOL autoScale; @end
While this isn't a long-term solution to the problem (and does introduce some extra work on part of the developer), the convenience of interacting with controls via GUI may be worth it if the rest of your ViewController is designed in the interface builder. Though the same control functionality can be delivered in code, some details—such as constraints and autolayout—can be easier to work with in the designer. I'm hoping Apple improves the experience of using frameworks in the interface builder, but for now, this workaround might provide you most of the functionality you're looking for. Read more about building custom controls >>