Live Xcode 的 Interface Builder UIView 子类 (IB_DESIGNABLE) 没有 drawRect:
Posted
技术标签:
【中文标题】Live Xcode 的 Interface Builder UIView 子类 (IB_DESIGNABLE) 没有 drawRect:【英文标题】:Live Xcode's Interface Builder UIView subclass (IB_DESIGNABLE) without drawRect: 【发布时间】:2014-09-25 14:55:21 【问题描述】:是否可以创建一个在 Xcode 中实时呈现的UIView
子类(通过添加here 解释的IB_DESIGNABLE
属性)但没有自定义drawRect:
方法?
我们有一个自定义的UIView
子类,它使用一些CAShapeLayer
s 添加到self.layer
进行绘图(因此,无需覆盖drawRect:
)。此类在 App 上运行良好,但不会在 Xcode 上呈现。
如果我们复制drawRect:
中的代码,它可以工作,但我们希望让绘图在图层上自动进行。
这个可以吗?
我也试过了
- (void)drawRect:(CGRect)rect
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(currentContext, self.myLayer1.frame.origin.x, self.myLayer1.frame.origin.y);
[self.myLayer1 renderInContext:currentContext];
CGContextMoveToPoint(currentContext, self.myLayer1.frame.origin.x, self.myLayer1.frame.origin.y);
[self.myLayer2 renderInContext:currentContext];
这似乎适用于设备,但不适用于 Xcode 的 IB。
【问题讨论】:
确保您的初始化(即设置CAShapeLayers
)代码也从initWithFrame:
调用。 IB 称之为预览。
是的,我也从那里调用它。没运气。你怎么知道IB使用initWithFrame:
? IB 预览时是否有调试视图代码的方法?
Editor
> Debug Selected Views
来自 Xcode 菜单。
Debug Selected Views 使 Xcode 在我的自定义视图中崩溃。 :-(
我将崩溃和 CALayer 实时渲染问题作为错误报告提交给 Apple。
【参考方案1】:
您可以在 IB 中预览 UIView
子类(使用 IB_DESIGNABLE
宏)即使 drawRect:
未被覆盖。
我在 XCode 6.1 中添加了您的 code 并将 OEProgressIndicator
添加到 xib
文件中。然后我通过在 commonProgressIndicatorInit
选择器中设置断点来调试它(使用菜单 Editor
/ Debug Selected View
)。
这就是为什么您在当前代码的预览中看不到任何内容的原因:当调用 commonProgressIndicatorInit
(来自 initWithFrame:(CGRect)frame
构造函数)时,frame
是等于CGRectZero
(x:0 y:0 width:0 height:0
),这样您的中心变量实际上等于(0, 0)
,半径为-1
。
在设备上,根据类的使用方式,您可能会被正确的帧直接调用,这就是为什么它可以在设备上工作但不能在 IB 中工作的原因。
为了解决这个问题,我将实现 layoutSubviews
选择器(从 UIView
覆盖它)来正确组织子层。当 frame
将从 CGRectZero
更改为 Interface Builder 中设置的正确值时,将调用此选择器。
【讨论】:
【参考方案2】:我一直在使用 - (void)prepareForInterfaceBuilder
方法来告诉 IB 实时渲染视图。
请看这里:Creating a Live View of a Custom Object
另外,你们是对的,这个功能也适用于 Objective-C。
你不一定要用drawRect
,你可以试试- (void)layoutSubviews
,好像行得通。将代码留在- (void)layoutSubviews
之类的地方只是为了实时渲染的问题是它的性能可能会降低等(例如,您可以在- (void)awakeFromNib
中做很多事情,但不会从实时渲染,所以请确保您也在 - (void)prepareForInterfaceBuilder
中进行了所有设置。
【讨论】:
这无助于渲染作为当前视图子层的自定义 CALayers。【参考方案3】:如果不查看所有代码,很难看出问题的根源是什么,但要回答您的问题,是的,您可以使用 IBInspectable / IBDesignable 而无需实现任何其他特定方法。我已经为使用许多图层且不进行任何绘图的视图执行此操作(为此使用嵌套图层)。
对于一个带圆角的快速测试示例 sn-p:
@IBDesignable
class MyView : UIView
@IBInspectable var cornerRadius:CGFloat
get return self.layer.cornerRadius
set self.layer.cornerRadius = newValue
@IBInspectable var borderWidth:CGFloat
get return self.layer.borderWidth
set self.layer.borderWidth = newValue
@IBInspectable var borderColor:UIColor
get return UIColor(CGColor: self.layer.borderColor)
set self.layer.borderColor = newValue.CGColor
有关渐变的简单示例,请参阅this post。
有关如何调试实时视图的说明,请参阅 WWDC §411 大约 22 分钟。
到目前为止,我看到的唯一限制是您可以在类扩展中添加可检查的属性,但它们只能在设备上正确呈现。
【讨论】:
感谢您的回答,但我们制作的this class 根本不起作用。如果你设法让它在 Xcode 6 上显示,请告诉我如何。请参阅我们尝试的两个drawRect
解决方法实现,但无济于事。
据我所知,这是 Swift 独有的功能。从我作为基线发布的链接开始,然后从那里分支。
IB_DESIGNABLE
自定义视图不是 Swift 独有的功能。 docs 明确指出它也适用于 Objective-C。如果只是,这不适用于自定义子 CALayers 的事实是 Objective-C only 错误。我reported it苹果。
啊,至少你有一个很好的解决方法——使用 Swift。
在我们的生产环境中使用 Swift 暂时不是一个选项。以上是关于Live Xcode 的 Interface Builder UIView 子类 (IB_DESIGNABLE) 没有 drawRect:的主要内容,如果未能解决你的问题,请参考以下文章
Interface Builder文件中的Xcode 6未知类
Xcode 和 Interface Builder 随机停止对话
Xcode 4.2 Interface Builder Dock 图标
Xcode 8 属性“隐藏”不会在 Interface Builder 中隐藏视图