Interface Builder是否有一种方法可以呈现不覆盖drawRect的IBDesignable视图: [英] Is there a way for Interface Builder to render IBDesignable views which don't override drawRect:

查看:99
本文介绍了Interface Builder是否有一种方法可以呈现不覆盖drawRect的IBDesignable视图:的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很少在我的UIView子类中覆盖drawRect,通常更喜欢使用预渲染图像设置 layer.contents 并且经常使用多个子图层或子视图并基于它们操作这些输入参数。有没有办法让IB渲染这些更复杂的视图堆栈?

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?

推荐答案

谢谢@zisoft在 prepareForInterfaceBuilder 上为我提供线索。 Interface Builder的渲染周期有一些细微差别,这是我的问题的来源,值得注意...

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. 确认:您不需要使用 -drawRect

在UIButton控制状态下设置图像有效。如果记住一些事情,任意层叠似乎都有用......

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


  1. IB使用 initWithFrame:

..不是的initWithCoder awakeFromNib 也未被调用。

..not initWithCoder. awakeFromNib is also NOT called.


  1. init ... 每次会话只调用一次

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

即每当你在文件中进行更改时,每次重新编译一次。更改IBInspectable属性时,不会再次调用init。但是......

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 被调用每次更改房产

  1. prepareForInterfaceBuilder is called on every property change

这就像在所有IBInspectables以及其他内置属性上使用KVO一样。您可以通过调用 _setup 方法自行测试,首先只从您的 init .. 方法开始。更改IBInspectable将不起作用。然后将调用添加到 prepareForInterfaceBuilder 。 Whahla!请注意,您的运行时代码可能需要一些额外的KVO,因为它不会调用 prepareForIB 方法。更多关于此...

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 ... 画得太快,设置图层内容等等。

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

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

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. 当IB无法呈现时,它不会使我们的组件空白,而是保留上一个成功的版本。

  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. 提示:保持活动监视器附近

我一直挂在几个不同的支持流程上,他们把整个机器都搞砸了跟他们。自由地应用强制退出

(更新:这真的没有是的,因为XCode6已经退出测试阶段。它很少挂起。)

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

更新

UPDATE


  1. 6.3.1似乎不喜欢IB版本中的KVO。现在,您似乎需要一个标志来捕获Interface Builder而不是设置KVO。这是正确的,因为 prepareForInterfaceBuilder 方法有效地KVO所有 IBInspectable 属性。不幸的是,这种行为在运行时没有以某种方式镜像,因此需要手动KVO。请参阅下面的更新示例代码。

  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子类示例



以下是工作IBDesignable UIButton 子类的一些示例代码。 ~~ 注意, prepareForInterfaceBuilder 实际上并不需要,因为KVO会监听我们相关属性的更改并触发重绘。 ~~更新:请参阅8以上。

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

这篇关于Interface Builder是否有一种方法可以呈现不覆盖drawRect的IBDesignable视图:的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆