最佳实践:呈现Subclassed UIView(使用自己的xib)作为UIViewControllers的子视图

时间:2011-08-19 10:51:41

标签: iphone ios uiview uiviewcontroller interface-builder

我的目标是,在自己的XIB中设置一个子类UIView(让我们称之为infoView),以便我可以在许多UIViewController中显示它。

问题: 到目前为止,当我将UIView添加到UIViewController时,我总是必须创建UIViewController文件的UIView .xib文件的所有者才能加载查看类似于:

...
//this is inside the calling UIViewController's method
// InfoView *infoView is ivar and a subclass of UIView
infoView = nil; 
NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:@"InfoView"
                                                owner:self options:nil];

for (id object in bundle) {
    if ([object isKindOfClass:[InfoView class]])
        infoView = (InfoView *)object;
}   

[[self view] addSubview:infoView]; 
...

但是我想在许多不同的UIView中使用相同的UIViewController,所以我实际上不想要文件的所有者,除了类本身。在ThomasM's question中,他将UIView本身设置为文件的所有者,但没有成功。

在答案中,我找到了将文件所有者设置为nil的解决方案。为此,我必须将Interface Builder对象库中的所有调用UIViewController对象添加到InfoView.xib文件中,并将它们与infoView个出口连接。

但这感觉不对。 所以我想在这里收集解决方案 将UIView与xib文件封装在一起,以便在许多不同的视图控制器中使用它。你们是如何处理的?

请求任何帮助。

编辑:

infoView类似于当用户按下其中一个视图控制器上的按钮时出现的叠加层。它不是View控制器的“主要”视图。它提供了有关其超级视图视图控制器视图的详细信息,之后将消失。我只用不同的内容填充infoView,抛出所有的调用视图控制器。

4 个答案:

答案 0 :(得分:3)

像Hollance answer指出我正在使用UINib

要使用它,请保留.xib文件所有者nil,并将infoView的所有自定义内容放在InfoView类实现的initWithCoder:方法中。如果您获得InfoView.xib之类的话,这将被调用:

// here InfoView is the name of the .xib file
UINib *infoNib = [UINib nibWithNibName:@"InfoView" bundle:nil];

NSArray *topLevelObjects = [infoNib instantiateWithOwner:self options:nil];

QInfoView *infoView = [topLevelObjects objectAtIndex:0];

答案 1 :(得分:1)

因此,您希望从要在多个UIView中使用的笔尖加载UIViewController,并且您希望将其连接到每个视图控制器上的插座。这是对的吗?

然后使用UIViewController属性创建一个FakeViewController子类(让我们称之为IBOutlet)。将FakeViewController设置为笔尖的文件所有者,并将UIView连接到其出口。

完成。

您只需要确保所有其他视图控制器也具有这些插座属性(尽管它们不需要是IBOutlets),但是nib加载器实际上并未检查以确保该类传入owner参数等于您在Interface Builder中指定的类名。所以你可以假装它。

哦,如果你是OS 4.0及更高版本,请使用UINib加载nib文件。

答案 2 :(得分:1)

另一种方法是根据NSObject创建自己的“控制器”来定义自己的生命周期(而不是标准的UIViewController生命周期)。

例如:

<强> BaseSubview.h:

@interface BaseSubview : NSObject {
    UIView* _view;
}

@property (nonatomic, retain) IBOutlet UIView* view;

- (void)myMethod;

@end

<强> BaseSubview.m:

#import "BaseSubview.h"

@implementation BaseSubview

@synthesize view = _view;

- (id)init
{
    self = [super init];
    if (self) {
        // ...
    }
    return self;
}

- (void)dealloc
{
    [_view removeFromSuperView];
    [super dealloc];
}

- (void)myMethod
{
    // view specific logic here
    _view.backgroundColor = [UIColor redColor];
}

@end

<强> InfoView.h:

#import "BaseSubview"
@interface InfoView : BaseSubview {
    UILabel* _labelInfo;
}

@property (nonatomic, retain) IBOutlet UILabel* labelInfo;

@end

<强> InfoView.m:

#import "InfoView.h"

@implementation InfoView

@synthesize labelInfo = _labelInfo;

- (id)init
{
    self = [super init];
    if (self) {
        // ...
    }
    return self;
}

- (void)myMethod
{
    // view specific logic here
    _labelInfo.text = @"current time...";
    [super myMethod];
}

@end

<强> InfoView.xib:

  • 文件所有者是InfoView
  • 像往常一样分配出口
  • 查看父级所有其他控件(例如标签等)

<强> HugeAndComplicatedViewController.h:

// ...
// among other var definitions
InfoView* _infoView;
// ...

HugeAndComplicatedViewController.m ,最有趣的部分:

// when you decide to show your view
// probably in loadView
_infoView = [[InfoView alloc] init];
[[NSBundle mainBundle] loadNibNamed:@"InfoView" owner:_infoView options:nil];
[self.view addSubview:_infoView.view];

// possibly perform specific logic
[_infoView myMethod];

// no need sub-view any more
// probably in dealloc
[_infoView release];

所以现在你有了自己的子视图,其逻辑和设计与“巨大而复杂”的视图控制器分开。它可以包含您当前项目所需的任何生命周期。

答案 3 :(得分:0)

infoView需要是一个子视图吗?

在viewController中

-(id) init {
    self = [super initWithNibName:@"myNib" bundle:nil]; 
    if (self) {
        // code here
    }
}