在另一个 xib 中使用 xib 对象

Posted

技术标签:

【中文标题】在另一个 xib 中使用 xib 对象【英文标题】:Using xib object inside another xib 【发布时间】:2011-02-23 18:31:18 【问题描述】:

我正在使用 IB 设计一个特定的按钮(带有一些标签,以及 imageView 和其他东西)。

然后我想在另一个 xib 中使用该 xib 对象(按钮),我有该按钮的 6 个对象。

我知道我可以使用类标识符以编程方式做到这一点,但是我必须定位我的标签和图像视图,并在代码中设置默认值和其他所有内容。

我想知道是否可以仅使用 IB 来做同样的事情? (当然我仍然会在代码中设置值,但我想在 xib 中设置标签/图像视图的位置以及所有其余部分)

谢谢

编辑

所以,我知道我最初要求的内容是不可能的。 我现在正在尝试的是这样的:

我创建了一个ButtonTest.xib。 在 Xib 内部,我有一个 UIView 和 3 个子视图(2 个标签和一个按钮)。 在检查器中,我将 UIView 类设置为ButtonTest。 在 ButtonTest.m 中,每个子视图都有 3 个出口,我在 IB 中连接它们。

接下来我有一个ButtonTestViewController.xib。 在其中我放了一个视图并将其在检查器中的类设置为ButtonTest。 我将该视图连接到 ButtonTestViewController.mButtonTest 内的 myTextView 插座

现在,这是 ButtonTestViewController.m viewDidLoad 中的代码:

- (void)viewDidLoad 
    [super viewDidLoad];

    NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"ButtonTest" owner:nil options:nil];
    ButtonTest *mainView = (ButtonTest*)[subviewArray objectAtIndex:0];

    self.myTextView = mainView;

我希望会发生的是,ButtonTestViewController.xib 中的视图会变成我在 ButtonTest.xib 中设计的视图。 这只是没有发生。发生的情况是 ButtonTestViewController.xib 中的视图保持不变。

值得一提的是,如果我添加:

[self.view addSubview:mainView];

除了现有视图之外,它确实添加了新视图。

知道如何做我想做的事吗?

最终我希望在ButtonTestViewController.xib 中有 6 个视图,看起来都像 ButtonTest.xib 模板,并且标签值将在代码中设置。

编辑2

好吧,伙计们,我照你说的做了,而且效果很好。 我现在遇到的唯一问题是ButtonTestViewController.xib 中的视图比ButtonTest.xib 中的视图大一点。 发生这种情况时,按钮上的标签看起来非常模糊。 当它们的大小相同时,一切都很好。

@ Ned - 我使用了您在 InitWithCoder 方法中发布的确切代码,但我将框架语句切换为:

self.bounds = mainView.frame;

我尝试在 IB 中使用内容模式尝试修复它,但无济于事。

当我像你发布的那样使用它时,意思是:

mainView.frame = self.bounds;

它根本不起作用,两个视图的大小保持不变。 在这里我尝试使用 resizeMask 但仍然没有工作。

想知道如何解决这两个问题? 谢谢大家!

编辑 3

我确实设法解决了其中一个问题,将ButtonTestViewController.xib 调整为ButtonTest.xib 视图大小。 这就是我所做的(使用代码解决模糊问题,取自here)

self.bounds = CGRectMake(0, 0, mainView.frame.size.width, mainView.frame.size.height);
        CGRect overlay2Frame = self.frame;
        overlay2Frame.origin.x = round(overlay2Frame.origin.x);
        overlay2Frame.origin.y = round(overlay2Frame.origin.y);
        self.frame = overlay2Frame;

另一个我仍然无法解决的问题。 ButtonTest.xib 中的视图不会变得更大以匹配其他视图。

【问题讨论】:

【参考方案1】:

您可以轻松地做到这一点。我这样做的方法是创建一个 UIView 子类(假设它称为“MyView.m”和“MyView.h”),然后创建一个名为“MyView.xib”的 nib。

首先,在 nib 中,单击 File's Owner,然后将类设置为“MyView”。这将使您班级中的 IBOutlets/Actions 出现在 IB 中。添加一个***视图(如果还没有)作为主视图,并将其他自定义元素(UILabels 和 UIImageViews)添加为主 UIView 的子视图。

接下来,添加以下代码,以便在 MyView 初始化时调用它(请记住,如果您从 nib 初始化,它将通过 - (id)initWithCoder:(NSCoder *)aDecoder 进行初始化)。

NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
UIView *mainView = [subviewArray objectAtIndex:0];

//Just in case the size is different (you may or may not want this)
mainView.frame = self.bounds;

[self addSubview:mainView];

它的作用是将视图层次结构从您的 nib 加载到 NSArray 中,并且由于您只有一个*** UIView,您只需将其添加为自定义 UIView 的子视图。

这允许您在 Interface Builder 中设计 UIView(以及 UIView 的其他子类)。

编辑:更新为 OP 的编辑。

我一直这样做的方式是首先按照上面的指示进行操作。一个区别是,在您的 ButtonTest 笔尖中,您将 UIView 的类更改为 ButtonTest,但我将文件所有者的类更改为 ButtonTest。然后,在ButtonTest.m 中,执行loadNibNamed 的操作。现在,要将该对象添加到 ButtonTestViewController.xib,添加一个 UIView(或 UIButton,无论 ButtonTest 是从哪个子类化的)并将类更改为 ButtonTest。

这有点混乱,所以我会尝试按文件分解。

ButtonTestViewController.xib:添加一个 UIButton(任何 ButtonTest 继承自)并将类更改为 ButtonTest

ButtonTest.m:在“initWithCoder”方法中,执行我上面的所有“loadNibNamed”操作

ButtonTest.xib: 将 File 的 Owner 类更改为 ButtonTest 并链接所有 IBOutlets 和 IBActions

【讨论】:

我认为 OP 已经走到了这一步。他在问如何随后在其他 .xib 文件中使用 MyView.xib 并能够完全编辑自定义界面。 马特是对的,我用一个新问题编辑了这个问题。请看一下。 我已经编辑了我的答案,使其更加清晰。我认为这就是你想要做的。 很好的答案。用另外 2 个小问题编辑了我的问题。非常感谢! 如果您将提供的代码放入 initWithCoder 中,您肯定会创建一个无限循环吗? (如果视图是从不同的 XIB 创建的)【参考方案2】:

你们中的一些人在评论中询问此解决方案是否不会创建无限循环,并且我没有足够的声誉来回答那里,所以这是我的答案:

如果您的 XIB 中的根视图将“自定义类”设置为 MyView,则存在循环。这会导致从 XIB 加载的视图调用 MyView 的初始化程序再次,从而创建无限循环。解决方案是“自定义类”应该是 UIView,并且只有文件所有者的类应该设置为 MyView(以便能够分配 IBOutlets 和 IBActions)。

【讨论】:

【参考方案3】:

Swift 3.0

用类创建 swift 文件

class ViewXIBfileClassView: UIView 
.....

使用 view:ViewXIBfileClassView

创建 Xib 文件

创建包装视图类

class ViewWrapper: UIView 

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
        let view = UINib(nibName: "ViewXIBfileClassView_file", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! viewXIBfileClassView
        self.addSubview(view)
        view.bindEdgesToSuperview()
    

UIView添加扩展

extension UIView 
    /// Adds constraints to the superview so that this view has same size and position.
    /// Note: This fails the build if the `superview` is `nil` – add it as a subview before calling this.
    func bindEdgesToSuperview() 
        guard let superview = superview else 
            preconditionFailure("`superview` was nil – call `addSubview(view: UIView)` before calling `bindEdgesToSuperview()` to fix this.")
        
        translatesAutoresizingMaskIntoConstraints = false
        ["H:|-0-[subview]-0-|", "V:|-0-[subview]-0-|"].forEach  visualFormat in
            superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: visualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
        
    

在您想要的所有 Xib 文件中使用 UIViewViewWrapper

【讨论】:

【参考方案4】:

例如,如果您的类是 UIButton 的子类,您可以在 Interface Builder 中打开 Library,当您搜索它时,它会在类选项卡下,您可以拖放。

您也可以只拖放一个 UIButton 并在检查器窗格中设置它的类。

但是,因为您有自己的 .xib 可能会搞砸,在这种情况下,请忽略我。

【讨论】:

以上是关于在另一个 xib 中使用 xib 对象的主要内容,如果未能解决你的问题,请参考以下文章

如何在另一个视图中加载 xib 文件?

无法在代码中更改 .xib UI 对象的框架

从 XIB 创建新的 UIView 对象

使用通过 ViewController 从 XIB 加载的子视图中的对象时出错

XIB 文件中对象的多个实例

如何在另一个 ViewController 中将带有 Xib 的 ViewController 显示为 SubView