如何将 UIView XIB“导入”到 UIViewController XIB?

Posted

技术标签:

【中文标题】如何将 UIView XIB“导入”到 UIViewController XIB?【英文标题】:How to "import" a UIView XIB into a UIViewController XIB? 【发布时间】:2013-03-19 20:06:14 【问题描述】:

我在这里看到了一些似乎符合我所追求的答案,但我无法让它们中的任何一个起作用。

MyView 是一个 UIView 子类,其中有一些图像和文本字段在MyView.xib 中布局和样式,并绑定到MyView.(h|m) 中的 IBOutlets。 File's Owner在XIB中没有设置,但是MyView是顶层对象的类。在运行时,我通过NSBundle'sloadNibNamed 将各种 MyViews 动态加载到某些视图控制器中。一切都很顺利。

但我有另一个视图控制器MyVC,在设计时我想填充几个 MyView 实例。凭直觉,我在MyVC.xib中布局了一个与MyView大小相同的UIView对象,将其类型设置为MyView,在MyVC.h中添加了IBOutlet声明,并连接了连接。

当我运行时,MyVC 显示没有 MyView。但是调试表明连接已经建立,视图确实是MyView,而MyView'sawakeFromNib确实执行了。而且我确信MyVC's MyView 在层次结构的顶部,因为我将它的背景设置为漂亮的鲜红色。那么MyView哪里有鬼?

【问题讨论】:

视图是awakeFromNib'd,但将调用它们的-initWithCoder init 方法,数据来自视图控制器xib而不是MyView.xib。如果这是有道理的...... 【参考方案1】:

最简单的解决方案是让MyView 有一个子视图,它是其余子视图的容器。这为您提供了 MyVC.xibMyView.xib 中的内容之间的单点联系,并允许您连接两个 xib 中的插座。

MyVC.xib中,将每个占位符视图的类设置为MyView

MyView.xib中,设置顶层视图的类为UIView。将文件所有者的类设置为MyView。如果您在MyView 上有任何在MyView.xib 中连接的插座,您需要将它们重新连接到文件的所有者,因为***视图不再有这些插座。

-[MyView initWithCoder:] 中,加载MyView.xib 并将其***视图添加为您的子视图。未经测试的示例:

+ (UINib *)nib 
    static dispatch_once_t once;
    static UINib *nib;
    dispatch_once(&once, ^
        nib = [UINib nibWithNibName:NSStringFromClass(self) bundle:[NSBundle bundleForClass:self]];
    );
    return nib;


- (id)initWithCoder:(NSCoder *)aDecoder 
    if (self = [super initWithCoder:aDecoder]) 
        NSArray *contents = [[self.class nib] instantiateWithOwner:self options:nil][0];
        UIView *containerView = contents[0];

        // Make sure the container view's size tracks my size.
        containerView.frame = self.bounds;
        containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
        self.autoresizesSubviews = YES;
        if ([self respondsToSelector:@selector(setTranslatesAutoresizingMaskIntoConstraints:)]) 
            self.translatesAutoresizingMaskIntoConstraints = YES;
            containerView.translatesAutoresizingMaskIntoConstraints = YES;
        
        // If you're using autolayout in both xibs, you should probably create
        // constraints between self and containerView here.

        [self addSubview:containerView];
    
    return self;

这样就可以将MyView的出口连接到MyVC.xib中的事物和MyView.xib中的事物,并且可以将MyVC.xibMyView.xib中的其他对象的出口连接到MyView 的实例。但是,您不能将MyVC.xib 中的其他对象的出口连接到MyView.xib 中的其他对象,反之亦然。

【讨论】:

我不确定我对此做了什么,但你的答案看起来不错。【参考方案2】:

ORIGINAL:重写 initWithCoder,正如下面的评论所说的那样是个坏主意

新建议:

使用您现在拥有的技术创建 MyVC 视图(MyView 实例基本上是空视图)

然后在MyVC的viewDidLoad:方法中:

使用您的 nib 创建新的 MyView 实例,为 MyView 中的每个实例创建一个

将每个空的(即占位符)MyViews 替换为您刚刚创建的那些,确保正确设置框架(设置任何属性/ivars,并使用 '- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2' 用子视图数组中的新视图替换旧视图)

【讨论】:

这不是简单的工作。当您加载笔尖时,它使用initWithCoder:。您必须采取预防措施以避免无限递归。 @robmayoff 猜猜这就是当你和大自然鬼混时会发生的事情!让我再试一次。

以上是关于如何将 UIView XIB“导入”到 UIViewController XIB?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 UITableView 作为子视图添加到 xib 中的 UIView?

如何将额外参数传递给链接到 XIB 文件的自定义 UIView?

如何将值从 XIB 传递到 UIView 初始化程序?

为 iCarousel 使用自定义 UIView

将 UIView 从 xib 添加到 UIScrollView

如何在不使用 Nib 的情况下实例化和调用 UIView 子类