【问题标题】:Best Practice: Presenting a Subclassed UIView (with own xib) as subview of UIViewControllers最佳实践:将子类 UIView(带有自己的 xib)呈现为 UIViewControllers 的子视图
【发布时间】:2011-10-30 12:52:27
【问题描述】:

我的目标是,在他自己的 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]; 
...

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

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

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

感谢任何帮助。

编辑:

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

【问题讨论】:

  • 您可能对我对“带有 xib 的可重用 UIView 小部件”问题的解决方案感兴趣,如我对此问题的回答中所述:stackoverflow.com/questions/5056219/…
  • @Bogatyr thx,这是一个很好的答案。

标签: iphone ios uiview uiviewcontroller interface-builder


【解决方案1】:

infoView 需要是子视图吗?

在您的视图控制器中:

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

【讨论】:

  • 是的,它必须是一个子视图。这对我的问题不起作用。 infoView 并不意味着是 viewController 的“主”视图。它更像是一个叠加层,通过推动例如按需出现。信息按钮。或多或少有点像 UIAlertView...
【解决方案2】:

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

然后创建一个带有IBOutlet 属性的UIViewController 子类(我们称之为FakeViewController)。将 FakeViewController 设置为 nib 的文件所有者,并将您的 UIView 连接到它的插座。

完成。

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

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

【讨论】:

  • 你明白我的意思!虽然我喜欢你使用 face ViewController 的想法,但这种方法感觉不对,因为在 apple doc's 他们说:“你不应该使用多个自定义视图控制器来管理同一视图层次结构的不同部分”。但是非常感谢您指出 UINib 类!
  • 在我的理解中,UIViewController 类似于带有额外层次逻辑的 UIView,我不需要在屏幕上显示部分视图。
  • FakeViewController 仅用于将 UIView 连接到您正在加载它的任何视图控制器的出口。所以你可以让 ViewControllerA 和 ViewControllerB 和 ViewControllerC 都加载你的 UIView,即使它们是不同的类。 UIView 认为它正在加载到 FakeViewController 中,但实际上并没有 FakeViewController 的实例,您实际上是在将其加载到 ViewControllerA/B/C 中。
  • 好的,谢谢!那么你认为这种方法比我上面描述的方法更有效吗?我将视图控制器对象添加到 xib 文件以将每个视图控制器的出口与视图挂钩?
  • 是的。虽然我不确定你是如何添加所有这些视图控制器的;作为真正的 View Controller 对象还是占位符?
【解决方案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];

【讨论】:

    【解决方案4】:

    还有一种方法是基于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];
    

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

    【讨论】:

      猜你喜欢
      • 2013-07-05
      • 2011-07-11
      • 2020-10-06
      • 2013-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-17
      相关资源
      最近更新 更多