一尘不染

接口构建器是否可以呈现不覆盖drawRect的IBDesignable视图:

swift

我很少在UIView子类中重写drawRect,通常更喜欢layer.contents使用预渲染图像进行设置,并且经常采用多个子层或子视图并根据输入参数进行操作。IB是否有方法呈现这些更复杂的视图堆栈?


阅读 230

收藏
2020-07-07

共1个答案

一尘不染

谢谢@zisoft为我提供的线索prepareForInterfaceBuilder。Interface
Builder的渲染周期有一些细微差别,这些细微差别是我遇到问题的根源,并且值得注意…

  1. 确认:您不需要使用-drawRect

在UIButton控件状态上设置图像有效。如果牢记一些注意事项,则任意层堆栈似乎都可以工作…

  1. IB用途initWithFrame:

..not initWithCoderawakeFromNib也不会被调用。

  1. init... 每个会话仅被调用一次

即,每当您在文件中进行更改时,每次重新编译一次。更改IBInspectable属性时,不会再次调用init。然而…

  1. prepareForInterfaceBuilder 每次属性更改都被调用

这就像在所有IBInspectables以及其他内置属性上包含KVO一样。您可以通过_setup首先调用您的方法来测试您自己init..。更改IBInspectable无效。然后将呼叫也添加到
prepareForInterfaceBuilder。哇!注意,您的运行时代码可能将需要一些额外的KVO,因为它不会调用该prepareForIB方法。下面的更多内容…

  1. init... 现在绘制,设置图层内容等还为时过早。

至少对于我的UIButton子类,调用[self setImage:img forState:UIControlStateNormal]在IB中无效。您需要prepareForInterfaceBuilder通过KVO挂钩或通过KVO挂钩调用它。

  1. 当IB无法渲染时,它不会使您的组件空白,而是保留最后一个成功的版本。

进行无效更改时,有时会造成混乱。检查构建日志。

  1. 提示:将活动监视器放在附近

我一直挂在几个不同的支持流程上,他们把整个机器拖走了。 大量申请Force Quit

(更新:自从XCode6退出beta版以来,这并不是真的。很少挂起了。)

更新

  1. 6.3.1在IB版本中似乎不喜欢KVO。现在,您似乎需要标记来捕获Interface Builder而不是设置KVO。可以,因为该prepareForInterfaceBuilder方法有效地KVO了所有IBInspectable属性。不幸的是,此行为未在运行时以某种方式反映出来,因此需要手动KVO。请参阅下面的更新的示例代码。

UIButton子类示例

下面是一个有效的IBDesignable UIButton子类的示例代码。
注意,prepareForInterfaceBuilder实际上并不是必需的,因为KVO会监听对我们相关属性的更改并触发重绘。
更新:请参见上面的第8点。

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
2020-07-07