Har*_*ngh 63 xcode objective-c interface-builder swift
我很少在我的UIView子类中覆盖drawRect,通常更喜欢layer.contents
使用预渲染图像进行设置,并且经常使用多个子图层或子视图,并根据输入参数对这些图层进行操作.有没有办法让IB渲染这些更复杂的视图堆栈?
Har*_*ngh 133
谢谢,@ zisoft为我提供了线索prepareForInterfaceBuilder
.Interface Builder的渲染周期有一些细微差别,这是我的问题的根源,值得注意......
-drawRect
. 在UIButton控制状态下设置图像有效.如果记住一些事情,任意层叠似乎都有用......
initWithFrame:
..不initWithCoder
. awakeFromNib
也没有被调用.
init...
每个会话只调用一次即每当你在文件中进行更改时,每次重新编译一次.更改IBInspectable属性时,不会再次调用init.然而...
prepareForInterfaceBuilder
每次改变财产都要求就像在所有IBInspectables以及其他内置属性上使用KVO一样.您可以通过_setup
调用您的init..
方法来自行测试,首先只能从您的方法中进行测试.更改IBInspectable将不起作用.然后添加呼叫 prepareForInterfaceBuilder
.Whahla!注意,您的运行时代码可能需要一些额外的KVO,因为它不会调用该prepareForIB
方法.更多关于此...
init...
现在绘制太快,设置图层内容等等.至少在我的UIButton
子类中,调用[self setImage:img forState:UIControlStateNormal]
对IB没有影响.你需要从prepareForInterfaceBuilder
KVO钩子或通过KVO钩子调用它.
当您进行无效的更改时,可能会感到困惑.检查构建日志.
我总是挂起几个不同的支持流程,他们把整个机器都拿下来. Force Quit
自由地申请.
(更新:自从XCode6退出测试版以来,情况并非真的如此.它很少再挂起)
UPDATE
prepareForInterfaceBuilder
方法有效地KVO所有IBInspectable
属性.不幸的是,这种行为在运行时没有以某种方式镜像,因此需要手动KVO.请参阅下面的更新示例代码.下面是一个有效的IBDesignable UIButton
子类的示例代码.~~ 注意,prepareForInterfaceBuilder
实际上不作为志愿监听改变我们的相关属性,并触发重绘需要.~~更新:见上文第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
Run Code Online (Sandbox Code Playgroud)
zis*_*oft 15
这个答案与覆盖drawRect有关,但也许它可以给出一些想法:
我有一个自定义的UIView类,它在drawRect中有复杂的绘图.您必须注意在设计时不可用的引用,即UIApplication.为此,我覆盖prepareForInterfaceBuilder
了我设置一个布尔标志的位置,我在drawRect中使用它来区分运行时和设计时:
@IBDesignable class myView: UIView {
// Flag for InterfaceBuilder
var isInterfaceBuilder: Bool = false
override init(frame: CGRect) {
super.init(frame: frame)
// Initialization code
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func prepareForInterfaceBuilder() {
self.isInterfaceBuilder = true
}
override func drawRect(rect: CGRect)
{
// rounded cornders
self.layer.cornerRadius = 10
self.layer.masksToBounds = true
// your drawing stuff here
if !self.isInterfaceBuilder {
// code for runtime
...
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是它在InterfaceBuilder中的外观:
您不必使用drawRect,而是可以在xib文件中创建自定义接口,在initWithCoder和initWithFrame中加载它,并在添加IBDesignable后在IB中进行实时渲染.查看这个简短的教程:https://www.youtube.com/watch?v = L97MdpaF3Xg
我认为layoutSubviews是最简单的机制.
这是Swift中一个(更简单)的例子:
@IBDesignable
class LiveLayers : UIView {
var circle:UIBezierPath {
return UIBezierPath(ovalInRect: self.bounds)
}
var newLayer:CAShapeLayer {
let shape = CAShapeLayer()
self.layer.addSublayer(shape)
return shape
}
lazy var myLayer:CAShapeLayer = self.newLayer
// IBInspectable proeprties here...
@IBInspectable var pathLength:CGFloat = 0.0 { didSet {
self.setNeedsLayout()
}}
override func layoutSubviews() {
myLayer.frame = self.bounds // etc
myLayer.path = self.circle.CGPath
myLayer.strokeEnd = self.pathLength
}
}
Run Code Online (Sandbox Code Playgroud)
我没有测试过这个片段,但之前使用过这样的模式.请注意,使用委托给计算属性的惰性属性来简化初始配置.
为了详细说明Hari Karam Singh 的回答,这张幻灯片进一步解释了:
http://www.splinter.com.au/presentations/ibdesignable/
然后,如果您没有在 Interface Builder 中看到您的更改,请尝试以下菜单:
不幸的是,调试我的视图冻结了 Xcode,但它应该适用于小型项目 (YMMV)。
归档时间: |
|
查看次数: |
34451 次 |
最近记录: |