Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Reusable UIView in storyboard and sizing constraints

I'm trying to create a reusable UIView in Swift that I can plug into my Storyboard view controllers. My key issue right now is that the reusable UIView "widget" doesn't fully fit into the UIView box in the storyboard. I followed this tutorial to set up the reusable UIView widget

  1. Created a subclass of UIView and a corresponding .xib -- and connected these:

    import UIKit
    
    class MyWidgetView: UIView {
    
    @IBOutlet var view: UIView!;
    
    required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder);
    
    NSBundle.mainBundle().loadNibNamed("MyWidgetView", owner: self, options: nil);
    self.addSubview(self.view);
    }
    
    }
    
  2. In the XIB, which is the interface file corresponding to the code above, I used UIView with Freeform size under the Simulated Metrics, and Scale to Fill under View mode.

  3. In the main storyboard, I added a UIView block (same rectangular shape) and changed the Class to MyWidgetView

  4. It works, but the components I created in the XIB look squished in the actual app, despite the fact that I used layout constraints in both the XIB and also the main storyboard.

See the screenshot. The pink part isn't supposed to appear, since that is just a color of the UIVIew on the main storyboard that I added to test the sizing. That UIView is actually MyWidgetView (after I changed the class in step 3. So in theory, since MyWidgetView == the UIView on the main storyboard, and that UIView has constraints that make it rectangular in the superview, then why is my widget squished? The blue part below should extend all the way right. Squished widget

like image 833
Uzumaki Naruto Avatar asked Aug 18 '15 00:08

Uzumaki Naruto


2 Answers

The actual view hierarchy loaded from the nib file in your code is added via self.addSubview(self.view). So, the frame of your self.view actually has no relationship with its parent, i.e. MyWidgetView.

You may choose either adding layout constraints through code or just setting its frame after being added as a subview. Personally, I prefer the latter. In my experiment, the following is what works for me. I am using Xcode 6.4, which I think is not the same one as yours.

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    if let nibsView = NSBundle.mainBundle().loadNibNamed("MyWidgetView", owner: self, options: nil) as? [UIView] {
        let nibRoot = nibsView[0]
        self.addSubview(nibRoot)
        nibRoot.frame = self.bounds
    }
}
like image 125
southp Avatar answered Nov 15 '22 06:11

southp


Alternatively the variable frame can be overridden. This code worked for me when CardImgText was set to files owner for the view.

class CardImgTxt: NSView {

    @IBOutlet var view: NSView!
    override var frame: NSRect{
        didSet{
            view.frame = bounds
        }
    }

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)


        // Drawing code here.
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        NSBundle.mainBundle().loadNibNamed("View", owner: self, topLevelObjects: nil)
        addSubview(view)
    }

}

if you are more interested in efficiency than real time updating. Then replace :

    override var frame: NSRect{
        didSet{
            view.frame = bounds
        }
    }

with:

override func viewDidEndLiveResize() {
    view.frame = bounds
}
like image 40
jiminybob99 Avatar answered Nov 15 '22 06:11

jiminybob99