Is there a way for Interface Builder to render IBDesignable views which don't override drawRect:

Hari Karam Singh

I very rarely override drawRect in my UIView subclasses, usually preferring to set layer.contents with pre-rendering images and often employing multiple sublayers or subviews and manipulating these based on input parameters. Is there a way for IB to render these more complex view stacks?

Hari Karam Singh

Thanks, @zisoft for the clueing me in on prepareForInterfaceBuilder. There a few nuances with Interface Builder's render cycle which were the source of my issues and are worth noting...

  1. Confirmed: You don't need to use -drawRect.

Setting images on UIButton control states works. Arbitrary layer stacks seem to work if a few things are kept in mind...

  1. IB uses initWithFrame:

..not initWithCoder. awakeFromNib is also NOT called.

  1. init... is only called once per session

I.e. once per re-compile whenever you make a change in the file. When you change IBInspectable properties, init is NOT called again. However...

  1. prepareForInterfaceBuilder is called on every property change

It's like having KVO on all your IBInspectables as well as other built-in properties. You can test this yourself by having the your _setup method called, first only from your init.. method. Changing an IBInspectable will have no effect. Then add the call as well to prepareForInterfaceBuilder. Whahla! Note, your runtime code will probably need some additional KVO since it won't be calling the prepareForIB method. More on this below...

  1. init... is too soon to draw, set layer content, etc.

At least with my UIButton subclass, calling [self setImage:img forState:UIControlStateNormal] has no effect in IB. You need to call it from prepareForInterfaceBuilder or via a KVO hook.

  1. When IB fails to render, it doesn't blank our your component but rather keeps the last successful version.

Can be confusing at times when you are making changes that have no effect. Check the build logs.

  1. Tip: Keep Activity Monitor nearby

I get hangs all the time on a couple different support processes and they take the whole machine down with them. Apply Force Quit liberally.

(UPDATE: This hasn't really been true since XCode6 came out of beta. It seldom hangs anymore)

UPDATE

  1. 6.3.1 seems to not like KVO in the IB version. Now you seem to need a flag to catch Interface Builder and not set up the KVOs. This is ok as the prepareForInterfaceBuilder method effectively KVOs all the IBInspectable properties. It's unfortunate that this behaviour isn't mirrored somehow at runtime thus requiring the manual KVO. See the updated sample code below.

UIButton subclass example

Below is some example code of a working IBDesignable UIButton subclass. ~~Note, prepareForInterfaceBuilder isn't actually required as KVO listens for changes to our relevant properties and triggers a redraw.~~ UPDATE: See point 8 above.

IB_DESIGNABLE
@interface SBR_InstrumentLeftHUDBigButton : UIButton

@property (nonatomic, strong) IBInspectable  NSString *topText;
@property (nonatomic) IBInspectable CGFloat topTextSize;
@property (nonatomic, strong) IBInspectable NSString *bottomText;
@property (nonatomic) IBInspectable CGFloat bottomTextSize;
@property (nonatomic, strong) IBInspectable UIColor *borderColor;
@property (nonatomic, strong) IBInspectable UIColor *textColor;

@end



@implementation HUDBigButton
{
    BOOL _isInterfaceBuilder;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self _setup];
        
    }
    return self;
}

//---------------------------------------------------------------------

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self _setup];
    }
    return self;
}

//---------------------------------------------------------------------

- (void)_setup
{
    // Defaults.  
    _topTextSize = 11.5;
    _bottomTextSize = 18;
    _borderColor = UIColor.whiteColor;
    _textColor = UIColor.whiteColor;
}

//---------------------------------------------------------------------

- (void)prepareForInterfaceBuilder
{
    [super prepareForInterfaceBuilder];
    _isInterfaceBuilder = YES;
    [self _render];
}

//---------------------------------------------------------------------

- (void)awakeFromNib
{
    [super awakeFromNib];
    if (!_isInterfaceBuilder) { // shouldn't be required but jic...

        // KVO to update the visuals
        @weakify(self);
        [self
         bk_addObserverForKeyPaths:@[@"topText",
                                     @"topTextSize",
                                     @"bottomText",
                                     @"bottomTextSize",
                                     @"borderColor",
                                     @"textColor"]
         task:^(id obj, NSDictionary *keyPath) {
             @strongify(self);
             [self _render];
         }];
    }
}

//---------------------------------------------------------------------

- (void)dealloc
{
    if (!_isInterfaceBuilder) {
        [self bk_removeAllBlockObservers];
    }
}

//---------------------------------------------------------------------

- (void)_render
{
    UIImage *img = [SBR_Drawing imageOfHUDButtonWithFrame:self.bounds
                                                edgeColor:_borderColor
                                          buttonTextColor:_textColor
                                                  topText:_topText
                                              topTextSize:_topTextSize
                                               bottomText:_bottomText
                                       bottomTextSize:_bottomTextSize];
    
    [self setImage:img forState:UIControlStateNormal];
}

@end

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Is it possible to make @IBDesignable override Interface Builder values?

From Dev

@IBDesignable view doesn't draw background color inside Interface Builder

From Dev

xcode Interface Builder not updating IBDesignable class

From Dev

Custom view created with Interface Builder does not render when called in other views

From Dev

Hiding some views in the interface builder

From Dev

Interface Builder Views not showing up

From Dev

Interface Builder Clipping Designable Views

From Dev

Controlling the targets Interface Builder builds for IB_DESIGNABLE / IBDesignable

From Dev

Is there a way to in Oracle to see what tables have data and which don't?

From Dev

Is there a way to find installed binary packages which don't have manpages?

From Dev

How to implement Visual Effect Views in Interface Builder?

From Dev

Xcode Interface Builder - views are vertically ambiguous

From Dev

Swap views but maintain constraints in Interface Builder

From Dev

Creating views programatically instead of using interface builder

From Dev

Xcode Interface Builder - views are vertically ambiguous

From Dev

Creating views programatically instead of using interface builder

From Dev

iOS: Create multiple dynamic views in interface builder

From Dev

Accessing properties of class defined as IBDesignable in drawRect: method

From Java

@IBDesignable error: IB Designables: Failed to update auto layout status: Interface Builder Cocoa Touch Tool crashed

From Dev

Xcode - is it possible to debug crashes in the Interface Builder's Live Rendering process (IBDesignable)?

From Dev

Best way to dynamically render different views in Android?

From Dev

JSTL don't render vars

From Dev

Don't loadOptions on initial render

From Dev

What is the correct way to override Marionette compositeview render

From Dev

What is the purpose of using interface when its methods don't have any implementation we have to override them every time?

From Dev

Is there a way to add comments to localized strings in Interface Builder?

From Dev

Zombie Objects From Views instantiated from Interface Builder

From Dev

Xcode6 Interface Builder has "hidden" my views?

From Dev

Storyboard / interface builder vs. full code views for iOS development

Related Related

  1. 1

    Is it possible to make @IBDesignable override Interface Builder values?

  2. 2

    @IBDesignable view doesn't draw background color inside Interface Builder

  3. 3

    xcode Interface Builder not updating IBDesignable class

  4. 4

    Custom view created with Interface Builder does not render when called in other views

  5. 5

    Hiding some views in the interface builder

  6. 6

    Interface Builder Views not showing up

  7. 7

    Interface Builder Clipping Designable Views

  8. 8

    Controlling the targets Interface Builder builds for IB_DESIGNABLE / IBDesignable

  9. 9

    Is there a way to in Oracle to see what tables have data and which don't?

  10. 10

    Is there a way to find installed binary packages which don't have manpages?

  11. 11

    How to implement Visual Effect Views in Interface Builder?

  12. 12

    Xcode Interface Builder - views are vertically ambiguous

  13. 13

    Swap views but maintain constraints in Interface Builder

  14. 14

    Creating views programatically instead of using interface builder

  15. 15

    Xcode Interface Builder - views are vertically ambiguous

  16. 16

    Creating views programatically instead of using interface builder

  17. 17

    iOS: Create multiple dynamic views in interface builder

  18. 18

    Accessing properties of class defined as IBDesignable in drawRect: method

  19. 19

    @IBDesignable error: IB Designables: Failed to update auto layout status: Interface Builder Cocoa Touch Tool crashed

  20. 20

    Xcode - is it possible to debug crashes in the Interface Builder's Live Rendering process (IBDesignable)?

  21. 21

    Best way to dynamically render different views in Android?

  22. 22

    JSTL don't render vars

  23. 23

    Don't loadOptions on initial render

  24. 24

    What is the correct way to override Marionette compositeview render

  25. 25

    What is the purpose of using interface when its methods don't have any implementation we have to override them every time?

  26. 26

    Is there a way to add comments to localized strings in Interface Builder?

  27. 27

    Zombie Objects From Views instantiated from Interface Builder

  28. 28

    Xcode6 Interface Builder has "hidden" my views?

  29. 29

    Storyboard / interface builder vs. full code views for iOS development

HotTag

Archive