Interface Builder是否有一种方法可以呈现不覆盖drawRect的IBDesignable视图: [英] Is there a way for Interface Builder to render IBDesignable views which don't override drawRect:
问题描述
我很少在我的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...
- 确认:您不需要使用
-drawRect
。
在UIButton控制状态下设置图像有效。如果记住一些事情,任意层叠似乎都有用......
Setting images on UIButton control states works. Arbitrary layer stacks seem to work if a few things are kept in mind...
- IB使用
initWithFrame:
..不是的initWithCoder
。 awakeFromNib
也未被调用。
..not initWithCoder
. awakeFromNib
is also NOT called.
-
init ...
每次会话只调用一次
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...
-
prepareForInterfaceBuilder
被调用每次更改房产
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...
-
init ...
画得太快,设置图层内容等等。
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.
- 当IB无法呈现时,它不会使我们的组件空白,而是保留上一个成功的版本。
- 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.
-
提示:保持活动监视器附近 罢工>
我一直挂在几个不同的支持流程上,他们把整个机器都搞砸了跟他们。自由地应用 强制退出
。
(更新:这真的没有是的,因为XCode6已经退出测试阶段。它很少挂起。)
(UPDATE: This hasn't really been true since XCode6 came out of beta. It seldom hangs anymore)
更新
UPDATE
- 6.3.1似乎不喜欢IB版本中的KVO。现在,您似乎需要一个标志来捕获Interface Builder而不是设置KVO。这是正确的,因为
prepareForInterfaceBuilder
方法有效地KVO所有IBInspectable
属性。不幸的是,这种行为在运行时没有以某种方式镜像,因此需要手动KVO。请参阅下面的更新示例代码。
- 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 theIBInspectable
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屋!