使用Interface Builder配置自定义UIView

时间:2011-04-11 04:55:44

标签: objective-c uiview interface-builder xib

许多人都提出过类似的问题,但是回答要么只是模糊不清,要么没有朝着我需要去的方向发展,所以我会尽可能具体地问这个问题。此问题的上下文适用于使用XCode 4进行iOS开发。

我有一个应用程序,我多次使用相同的Widget。在这个简单的练习中,小部件将是一个固定大小的红色框,顶部有一个标签,根视图控制器将改变,但你可以想象它有很多ImageViews和ScrollViews,看起来很漂亮。最后一点是关键,因为非编码艺术设计师希望能够全局调整此视图,而无需在UI的每个重复部分上反复执行相同的操作。

在应用程序中,我已经用单个UIView替换了用于构成窗口小部件的ImageViews和ScrollViews,并使用InterfaceBuilder将自定义类设置为Widget。我在根视图控制器中有这些Widget对象正确连接的插座。 Widget类是UIView的子类,代码如下:

@interface Widget : UIView {
    UILabel     *label;
}

@property (nonatomic, retain) IBOutlet  UILabel *label;
@property (nonatomic, copy) NSString *labelName;
@end


@implementation Widget
@synthesize label, labelName;

- (id)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder:aDecoder])) { 
        // This is the code that I want to disappear    
        CGRect pos = CGRectMake(5, 5, 90, 30);
        label = [[UILabel alloc] initWithFrame:pos];
        [self addSubview:label];
        self.backgroundColor = [UIColor redColor];
    }
    return self;
}

- (NSString *)labelName {
    return label.text;
}

// This live updates the label in this custom view
- (void)setLabelName:(NSString *)name {
    label.text = name;
}

- (void)dealloc {
    [super dealloc];
}
@end

代码效果很好,我可以直接从主视图控制器更新自定义视图中的文本。但是,initWithCoder中的四行代码是问题所在。还记得设计师吗?我有他们可以使用Interface Builder工作他们的魔力,但我不能为我的生活弄清楚如何让UIView从他们设计的笔尖加载自己。手动尝试和复制永远单个项目的定位和属性并不是非常令人兴奋和非常耗时(是的,我知道如果我没有写这篇文章,我现在就完成了。)

非常简单,如何获取任意.xib文件并让它完成我在initWithCoder中手工处理的工作?我假设在这一点上为UILabel连接IBOutlet是微不足道的,但如果我过于乐观,请对此发表评论。

作为第二个问题,一旦在真实用户界面上启动并运行,我就会把UIScrollViews连接起来。 Widget是否成为UIScrollViewDelegate或此代码停在何处。根视图控制器应该忽略这一点,但将传统上放在View Controller中的代码放入UIView对象中感觉不合适。

3 个答案:

答案 0 :(得分:4)

在控制器中声明IBOutlet(IBOutlet UIView * Widget;)。将Widget视图(来自设计器)放在控制器的xib中(如果控制器没有xib,则可以为控制器创建或指定新的xib)。然后将此视图连接到上面的IBOutlet。如果你想避免挂钩标签,滚动视图等等。每当设计师进行更改时,你必须更换整个xib而不是仅仅替换视图。

答案 1 :(得分:0)

是的,您应该使用标签连接IBOutlet,然后设计人员可以从Interface Builder中定位标签。

关于UIScrollViewDelegate,您还应该为滚动视图设置IBOutlet,然后在控制器中设置widgetView.scrollView.delegate = self,以设置当前控制器作为滚动视图的委托。

作为替代方案,您可以使Widget视图成为滚动视图的委托,但在我看来,您可以通过这样做来破坏MVC合规性(处理滚动视图事件的代码是控制器代码)。 / p>

答案 2 :(得分:0)

关于你的第一个问题,我认为你在寻找的是:

Widget *widget = nil;
NSArray *nibItems = [[NSBundle mainBundle] loadNibNamed:@"Widget" owner:self options:nil];
for (id o in nibItems) {
    if ([o isTypeOfClass:[Widget class]]) {
        widget = (Widget *)id;
    }
}

// Do whatever you want with the Widget...

通过bundle从nib加载它将保留设计器在界面构建器中的工作,并将触发对initWithCoder的调用。

至于第二个问题,你有两个选择。您可以在nib中设置UIScrollView的委托属性(它是IB可访问的属性),也可以在initWithCoder方法的代码中手动设置它。这取决于所期望的行为。