Using xib object inside another xib

﹥>﹥吖頭↗ 提交于 2019-12-17 18:36:44

问题


I'm designing using IB a specific button (with some labels,and imageView and other stuff).

I would like then to use that xib object (the button) in another xib, where I have 6 objects of that button.

I know I can do that programmatically using the Class Identifier, but then I have to position my lables and image view, and set the default values and everything else in code.

I'm wondering if it's possible to do the same thing using just the IB ? (of course I would still set the values in code, but I want to positions of the lables/imageView and all the rest to be set in the xib)

Thanks

Edit

So, I understand what I asked for at first is not possible. What I'm trying now is like that :

I created a ButtonTest.xib. Inside the Xib I have a UIView and 3 subviews (2 lables and a button). In the inspector I set the UIView class to ButtonTest. Inside ButtonTest.m I have 3 outlets for each of the subviews, which I connect in IB.

Next I have a ButtonTestViewController.xib. Inside it I put one view and set it's class in the inspector to be ButtonTest. I connect that view to a myTextView outlet inside ButtonTestViewController.m of class ButtonTest

Now, this is the code inside 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;
}

What I hoped would happen, is that the view in ButtonTestViewController.xib would become the view I designed in ButtonTest.xib. This just isn't happening. what happens is that the view inside ButtonTestViewController.xib stays the same.

Worth mentioning, is that if I add:

[self.view addSubview:mainView];

It does add the new view, besides the existing one.

Any idea how to do what I want ?

Eventually I would like to have 6 views in ButtonTestViewController.xib, all would look like the ButtonTest.xib template, and the lables values will be set in code.

Edit2

Ok, guys I did everything you said and it worked like a charm. The only problem I have right now with this issue is when the view in ButtonTestViewController.xib is a little bigger then view in ButtonTest.xib. When that happens, The lable on the button look extremely blurry. When they are both the same size, it's all good.

@ Ned - I used the exact code you posted in my InitWithCoder method, except I switched the frame sentence to this :

self.bounds = mainView.frame;

I tried playing with the content mode in IB trying to fix it, to no avail.

When I do use it like you posted, meaning :

mainView.frame = self.bounds;

It's not working at all, and both views' sizes stay the same. Here I tried playing with the resizeMask but still didn't work.

And idea how to fix these 2 issues ? Thanks guys!

Edit 3

I did manage to fix one of the issues, resizing the ButtonTestViewController.xib to the ButtonTest.xib view size. This is what I did (using code to solve the blurry issue, taken from 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;

The other issue I still can't solve. the view in ButtonTest.xib just won't get bigger to match the other view.


回答1:


You can do this, and pretty easily. The way I do this is create a UIView subclass (let's say it's called "MyView.m" and "MyView.h"), and then a nib called "MyView.xib".

First, in the nib, click File's Owner, and set the class to "MyView". This will make it so IBOutlets/Actions from your class show up in IB. Add a single top-level view (if it doesn't have one already) as your main view, and add your other custom elements (UILabels and UIImageViews) as subviews of the main UIView.

Next, add the following code so that it gets called when MyView is initialized (remember, if you initialize from a nib it'll get initialized via - (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];

What this does is loads the view hierarchy from your nib into the NSArray, and since you only had one top-level UIView, you just add that as a subview of your custom UIView.

This allows you to design UIViews (and other subclasses of UIView) in Interface Builder.

EDIT: Updated to OP's edit.

The way I've always done this is by first following my directions above. One difference is that in your ButtonTest nib you're changing the class of the UIView to ButtonTest, but I change the File Owner's class to ButtonTest. Then, inside ButtonTest.m, do the loadNibNamed stuff. Now, to add that object to ButtonTestViewController.xib, add a UIView (or UIButton, whatever ButtonTest is subclassed from) and change the class to ButtonTest.

This is a little confusing, so I'll try to break it up by file.

ButtonTestViewController.xib: Add a UIButton (of whatever ButtonTest inherits from) and change the class to ButtonTest

ButtonTest.m: Inside the "initWithCoder" method, do all of the "loadNibNamed" stuff I have above

ButtonTest.xib: Change File's Owner class to ButtonTest and link up all IBOutlets and IBActions




回答2:


Some of you ask in comment if this solution doesn't create infinite loop and I don't have enough reputation to answer there, so here is my answer:

The loop exist if root view in your XIB has "Custom class" set to MyView. This causes the situation where view loaded from XIB invokes initializer of MyView again and therefore, creates infinite loop. The solution is that "Custom class" should be UIView and only File Owner's class should be set to MyView (to be able to assign IBOutlets and IBActions).




回答3:


Swift 3.0

create swift file with class

class ViewXIBfileClassView: UIView {
.....
}

create Xib file with view:ViewXIBfileClassView

create wrapper view class

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()
    }
}

add extension to 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]))
        }
    }
}

Use UIView with ViewWrapper inside all Xib files you want




回答4:


If your class is a subclass of UIButton for example, you can open the Library in Interface Builder and it will be under the classes tab when you search for it and you can drag and drop.

You can also just drag/drop a UIButton and set its class in the inspector pane.

However, because you have your own .xib that might mess it up, in which case just ignore me.



来源:https://stackoverflow.com/questions/5095359/using-xib-object-inside-another-xib

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!