Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Saturday, August 6, 2016

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

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


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 same tools for scenes to design/layout a reusable view/control. So I created my first ever xib for my view subclass and painted it up:

enter image description here

I have my outlets connected and constraints setup, just like I'm used to doing in the storyboard. I set the class of my File Owner to that of my custom UIView subclass. So I assume I can instantiate this view subclass with some API, and it will configured/connected as shown.

Now back in my storyboard, I want to embed/reuse this. I'm doing so in a table view prototype cell:

enter image description here

I've got a view. I've set the class of it to my subclass. I've created an outlet for it so I can manipulate it.

The $64 question is where/how do I indicate that it's not enough to just put an empty/unconfigured instance of my view subclass there, but to use the .xib I created to configure/instantiate it? It would be really cool, if in XCode6, I could just enter the XIB file to use for a given UIView, but I don't see a field for doing that, so I assume I have to do something in code somewhere.

(I do see other questions like this on SO, but haven't found any asking for just this part of the puzzle, or up to date with XCode6/2015)

Update

I am able to get this to kind of work by implementing my table cell's awakeFromNib as follows:

- (void)awakeFromNib  {      // gather all of the constraints pointing to the uncofigured instance      NSArray* progressConstraints = [self.contentView.constraints filteredArrayUsingPredicate: [NSPredicate predicateWithBlock:^BOOL(id each, NSDictionary *_) {          return (((NSLayoutConstraint*)each).firstItem == self.progressControl) || (((NSLayoutConstraint*)each).secondItem == self.progressControl);      }]];      // fetch the fleshed out variant      ProgramProgressControl *fromXIB = [[[NSBundle mainBundle] loadNibNamed:@"ProgramProgressControl" owner:self options:nil] objectAtIndex:0];      // ape the current placeholder's frame      fromXIB.frame = self.progressControl.frame;      // now swap them      [UIView transitionFromView: self.progressControl toView: fromXIB duration: 0 options: 0 completion: nil];      // recreate all of the constraints, but for the new guy      for (NSLayoutConstraint *each in progressConstraints) {          id firstItem = each.firstItem == self.progressControl ? fromXIB : each.firstItem;          id secondItem = each.secondItem == self.progressControl ? fromXIB : each.secondItem;          NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem: firstItem attribute: each.firstAttribute relatedBy: each.relation toItem: secondItem attribute: each.secondAttribute multiplier: each.multiplier constant: each.constant];          [self.contentView addConstraint: constraint];      }      // update our outlet      self.progressControl = fromXIB;  }  

Is this as easy as it gets then? Or am I working too hard for this?

Answer by Segev for How to embed a custom view xib in a storyboard scene?


You're almost there. You need to override initWithCoder in your custom class you assigned the view to.

- (id)initWithCoder:(NSCoder *)aDecoder {      if ((self = [super initWithCoder:aDecoder])) {          [self addSubview:[[[NSBundle mainBundle] loadNibNamed:@"ViewYouCreated" owner:self options:nil] objectAtIndex:0]];      }      return self; }  

Once that's done the StoryBoard will know to load the xib inside that UIView.

Here's a more detailed explanation:

This is how your UIViewController looks like on your story board: enter image description here

The blue space is basically a UIView that will "hold" your xib.

This is your xib:

enter image description here

There's an Action connected to a button on it that will print some text.

and this is the final result:

enter image description here

The difference between the first clickMe and the second is that the first was added to the UIViewController using the StoryBoard. The second was added using code.

Here's an example project for your to play with: http://tinyurl.com/muqeuue

Answer by Dustin for How to embed a custom view xib in a storyboard scene?


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.

Answer by Yuyutsu for How to embed a custom view xib in a storyboard scene?


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.

Answer by TomSwift for How to embed a custom view xib in a storyboard scene?


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;  }  

Answer by brandonscript for How to embed a custom view xib in a storyboard scene?


A pretty cool and reusable way of doing this Interface Builder and Swift 2:

  1. Create a new class like so:

    import Foundation  import UIKit  @IBDesignable    class XibView: UIView {        @IBInspectable var xibName: String?        override func awakeFromNib() {          if xibName != nil {              if let xib = NSBundle.mainBundle().loadNibNamed(self.xibName, owner: self, options: nil) {                  if let views = xib as? [UIView] where views.count > 0 {                      self.addSubview(xib[0] as! UIView)                  }              }          }      }  }  
  2. In your storyboard, create a view that will house the .xib file. Give it a class name of XibView:

  3. In the property inspector of the new XibView, set the name of your .xib (without the file extension):

One thing to note: This assumes that you're matching the .xib frame to its container. If you do not, or need it to be resizable, you'll need to add in some programmatic constraints or modify the subview's frame to fit. The solution I elected to use implements :

xibView.snp_makeConstraints(closure: { (make) -> Void in      make.edges.equalTo(self)  })  

Answer by smileBot for How to embed a custom view xib in a storyboard scene?


  • Create Xib file File > New > New File > iOS > User Interface > View
  • Create custom UIView class File > New > New File > iOS > Source > CocoaTouch
  • Assign the Xib file's identity to the custom view class
  • In viewDidLoad of the view controller initialize the Xib and it's associated file using loadNibNamed: on NSBundle.mainBundle and the first view returned can be added as a subview of self.view.
  • The custom view loaded from the nib can be saved to a property for setting the frame in viewDidLayoutSubviews. Just set the frame to self.view's frame unless you need to make it smaller than self.view.

    class ViewController: UIViewController {    weak var customView: MyView!    override func viewDidLoad() {      super.viewDidLoad()      self.customView = NSBundle.mainBundle().loadNibNamed("MyView", owner: self, options: nil)[0] as! MyView      self.view.addSubview(customView)      addButtonHandlerForCustomView()  }    private func addButtonHandlerForCustomView() {      customView.buttonHandler = {          [weak self] (sender:UIButton) in          guard let welf = self else {              return          }          welf.buttonTapped(sender)      }  }    override func viewDidLayoutSubviews() {      self.customView.frame = self.view.frame  }      private func buttonTapped(button:UIButton) {    }  

    }

  • Also, if you want to talk back from the Xib to your viewController instance then create a weak property on the custom view's class.

    class MyView: UIView {    var buttonHandler:((sender:UIButton)->())!    @IBAction func buttonTapped(sender: UIButton) {      buttonHandler(sender:sender)  }  

    }

Here's the project on github


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.