How to embed a custom view xib in a storyboard scene?

前端 未结 11 544
生来不讨喜
生来不讨喜 2021-01-29 21:33

I\'m relatively new in the XCode/iOS world; I\'ve done some decent sized storyboard based apps, but I didn\'t ever cut me teeth on the whole nib/xib thing. I want to use the sam

相关标签:
11条回答
  • 2021-01-29 22:06

    Here's the answer you've wanted all along. You can just create your CustomView class, have the master instance of it in a xib with all the subviews and outlets. Then you can apply that class to any instances in your storyboards or other xibs.

    No need to fiddle with File's Owner, or connect outlets to a proxy or modify the xib in a peculiar way, or add an instance of your custom view as a subview of itself.

    Just do this:

    1. Import BFWControls framework
    2. Change your superclass from UIView to NibView (or from UITableViewCell to NibTableViewCell)

    That's it!

    It even works with IBDesignable to render your custom view (including the subviews from the xib) at design time in the storyboard.

    You can read more about it here: https://medium.com/build-an-app-like-lego/embed-a-xib-in-a-storyboard-953edf274155

    And you can get the open source BFWControls framework here: https://github.com/BareFeetWare/BFWControls

    And here's a simple extract of the code that drives it, in case you're curious: https://gist.github.com/barefeettom/f48f6569100415e0ef1fd530ca39f5b4

    Tom

    0 讨论(0)
  • 2021-01-29 22:06

    The "correct" answer is that you are not meant to make re-usable views with corresponding nibs. If a view subclass is valuable as a reusable object it rarely will need a nib to go with it. Take for example every view subclass provided by UIKit. Part of this thinking is a view subclass that is actually valuable wont be implemented using a nib, which is the general view at Apple.

    Usually when you use a view in nib or storyboard you will want to tweak it graphically for the given use case anyway.

    You might consider using "copy paste" for recreating same or similar views instead of making separate nibs. I this believe accomplishes the same requirements and it will keep you more or less in line with what Apple is doing.

    0 讨论(0)
  • 2021-01-29 22:12

    A little bit more swifty version of @brandonscript 's idea with early return:

    override func awakeFromNib() {
    
        guard let xibName = xibName,
              let xib = Bundle.main.loadNibNamed(xibName, owner: self, options: nil),
              let views = xib as? [UIView] else {
            return
        }
    
        if views.count > 0 {
            self.addSubview(views[0])
        }
    
    }
    
    0 讨论(0)
  • 2021-01-29 22:18

    You need to implement awakeAfterUsingCoder: in your custom UIView subclass. This method allows you to exchange the decoded object (from the storyboard) with a different object (from your reusable xib), like so:

    - (id) awakeAfterUsingCoder: (NSCoder *) aDecoder
    {
        // without this check you'll end up with a recursive loop - we need to know that we were loaded from our view xib vs the storyboard.
        // set the view tag in the MyView xib to be -999 and anything else in the storyboard.
        if ( self.tag == -999 )
        {
            return self;
        }
    
        // make sure your custom view is the first object in the nib
        MyView* v = [[[UINib nibWithNibName: @"MyView" bundle: nil] instantiateWithOwner: nil options: nil] firstObject];
    
        // copy properties forward from the storyboard-decoded object (self)
        v.frame = self.frame;
        v.autoresizingMask = self.autoresizingMask;
        v.translatesAutoresizingMaskIntoConstraints = self.translatesAutoresizingMaskIntoConstraints;
        v.tag = self.tag;
    
        // copy any other attribtues you want to set in the storyboard
    
        // possibly copy any child constraints for width/height
    
        return v;
    }
    

    There's a pretty good writeup here discussing this technique and a few alternatives.

    Furthermore, if you add IB_DESIGNABLE to your @interface declaration, and provide an initWithFrame: method you can get design-time preview to work in IB (Xcode 6 required!):

    IB_DESIGNABLE @interface MyView : UIView
    @end
    
    @implementation MyView
    
    - (id) initWithFrame: (CGRect) frame
    {
        self = [[[UINib nibWithNibName: @"MyView"
                                bundle: [NSBundle bundleForClass: [MyView class]]]
    
                 instantiateWithOwner: nil
                 options: nil] firstObject];
    
        self.frame = frame;
    
        return self;
    }
    
    0 讨论(0)
  • 2021-01-29 22:24

    You just have to drag and drop UIView in your IB and outlet it and set

    yourUIViewClass  *yourView =   [[[NSBundle mainBundle] loadNibNamed:@"yourUIViewClass" owner:self options:nil] firstObject];
    [self.view addSubview:yourView]
    

    enter image description here

    Step

    1. Add New File => User Interface => UIView
    2. Set Custom Class - yourUIViewClass
    3. Set Restoration ID - yourUIViewClass
    4. yourUIViewClass *yourView = [[[NSBundle mainBundle] loadNibNamed:@"yourUIViewClass" owner:self options:nil] firstObject]; [self.view addSubview:yourView]

    Now you can customize view as you want.

    0 讨论(0)
提交回复
热议问题