AutoLayout not working with embedded Xib file - ios

I have a nib with a label in it, which is centered vertically and horizontally using Auto Layout. I declared a subclass of UIView and loaded the nib file in it.
I then added an UIView to my main view controller and assigned the new subclass to it. The problem is that the label of the nib file is not centered to the view, it doesn't follow the AutoLayout constraints.
Download test project. Why is this happening?

Here's how you should write you custom class:
import UIKit
class CustomView: UIView {
#IBOutlet var view: UIView!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
view = NSBundle.mainBundle().loadNibNamed("CustomView", owner: self, options: nil).first as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
view.translatesAutoresizingMaskIntoConstraints = true
view.frame = bounds
self.addSubview(self.view)
}
}
Here's a working example:
Testxibautolayout2.zip

As you are loading the xib programmatically, it takes the original frame size of xib that is designed in storyboard which is 600x600. Make an outlet property of your custom view and change its frame after you load the xib! –
In your case you have to do it like:
import UIKit
class CustomView: UIView {
#IBOutlet var testView: UIView!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
NSBundle.mainBundle().loadNibNamed("CustomView", owner: self, options: nil)
self.addSubview(self.testView)
self.testView.frame=CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)
//or
self.testView.frame=self.bounds
}
}

Related

Instantiating custom xib programmatically ends with infinite loop

I request apologies in advance in the case this question is very elemental or the answer is obvious.
I have a custom xib, that works very well when used with the storyboard interface builder. The custom xib is implemented like the classical samples you can find across the internet:
I have a CustomView.swift class
a CustomView.xib file.
The FileOwner of the CustomView.xib file is set to the CustomView.class. Then this xib file has a couple of outlets for the views used in the xib. Something like the following:
#IBDesignable
class CustomView: UIView {
#IBOutlet weak var view1: UIView!
#IBOutlet weak var view2: UIView!
required init?(coder aDecoder: NSCoder) {
//When loaded from storyboard.
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
//When loaded from code
super.init(frame: frame)
commonInit()
}
func commonInit() {
if let view = Bundle.main.loadNibNamed(self.nibName, owner: self, options: nil)?.first as? UIView {
view.frame = self.bounds
self.addSubview(view)
view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
}
func renderViews()
//A lot of stuff is done here.
}
}
As said, this works very well when using the Storyboard designer to insert the custom xib in the layout of an UIController. But I need to use the same xib on another place, and I need to instantiate and insert it programmatically in a container view multiple times.
I tried different approaches to instantiate the xib and add it as a subview of another view, for example:
class AnotherView: UIView
(...)
func instantiateXib(){
let view = CustomView()
self.addSubView(view)
}
}
or
class AnotherView: UIView
(...)
func instantiateXib(){
let nib = UINib(nibName: "CustomView", bundle: nil).instantiate(withOwner: nil, options: nil)
let view = nib.first as! CustomView
self.addSubView(view)
}
}
or many other ways that I found across the internet, but all of them end with an infinite loop, because the method init?(coder aDecoder: NSCoder) of the xib, calls the commonInit method that instantiates again an instance of the xib, and so on.
I suspect the solution is obvious, but I'm struggling to find it.
May you point me in the right direction? Thank you in advance!

Loading a custom view with a nib causes constraints being removed

Overview
I created a custom view class and an associated nib. When I try to load it in another view controller, it loads it but the constraints are removed.
What I found
Before marking this as a duplicate... I read plenty of questions on StackOverflow of people having the same issues but the ones in swift were either unanswered either non-working. I tried everything.
What I'm doing
I have a view controller (which happens to be a keyboardviewcntroller but on a regular one I still have the problem) with an associated nib and a custom uiView with its associated nib.
KeyboardViewController:
I associated with my Keyboard view controller a zip file. His file owner is KeyboardViewController.
In my KeyboardViewController I have the basic code you get by creating a keyboard target and then I added the custom view outlet before the viewDidLoad
#IBOutlet weak var vieww: Custom!
and inside of my viewDidLoad I loaded my nib
let nib = UINib(nibName: "nibbb", bundle: nil)
let objects = nib.instantiate(withOwner: self, options: nil)
view = objects[0] as? UIView
Custom view
My custom view has an associated nib too. Its file owner is Custom (my new class). In the nib I put a button and a label as shown in the picture below and I added some constraints.
In the Custom class, I put the following code which includes outlets and the init of the class.
#IBOutlet weak var label: UILabel!
#IBOutlet weak var button: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit(){
Bundle.main.loadNibNamed("Custom", owner: self, options: nil)
addSubview(label)
label.frame = self.bounds
label.autoresizingMask = [.flexibleHeight, .flexibleWidth]
addSubview(button)
button.frame = self.bounds
button.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
}
This is the output i get:
and of course, it's not what I wanted.
Question
How do I load a custom UIView nib from another view controller without having my constraints being messed up?
The reason your constraints are not working as expected is because in the commonInit function sets both the label and button to be the same size as the view is.
You should declare a UIView property and then replace the content of commonInit function:
var contentView: UIView!
private func commonInit() {
if let nib = Bundle.main.loadNibNamed("Custom", owner: self, options:nil)?.first as? UIView {
contentView = nib
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
contentView.frame = bounds
addSubview(contentView)
}
}

how to fit xib view width to superView width

I have a xib view like this ,and its width is 728px now.
image1
iamge2
I apply it into my mainView like this (my mainView's width is 1024px),but its width doesn't fit my main view's width.
image3
image4
image5
what should I do? anyone can help me?
code
class common: UIView {
// コードから呼び出す際に使用される
override init(frame: CGRect) {
super.init(frame: frame)
loadNib()
}
// Storyboardから利用する際に使用される
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadNib()
}
// 上記どちらのinitからも使用される共通関数で、xibファイルを呼び出す。
func loadNib() {
// 第1引数のnameには、xibファイル名
// ownerはself固定
// optionsはここではnil
let view = Bundle.main.loadNibNamed("common", owner: self, options: nil)?.first as! UIView
view.frame = self.bounds
self.addSubview(view)
}
}
In your .xib file, give IBOutlet to view like this:
IBOutlet:
#IBOutlet var contentView: UIView!
You need to add autoresizingMask to the view you are loading.
Here, see the change in code.
Try below code for the resizing:
func loadNib() {
Bundle.main.loadNibNamed("common", owner: self, options: nil)
addSubview(contentView)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}

Why there is an extra UIView when adding an XIB view from the Interface Builder

I created a Tag view from XIB (see the document outline on the left) which contains only one subview which is a UILabel. The constraints set for the content view is its width and height should equal to the label, the label should use its intrinsic value.
I placed this Tag inside another view created from XIB, however, when I run the app there is an extra UIView underneath the Tag.
I do not understand what causes this additional one UIView. Everything describes above is done inside the Interface Builder, expect the file's owner is done inside the code editor.
Large image here, https://i.stack.imgur.com/PLFz7.jpg
#IBDesignable class DCCardTagView: UIView {
#IBOutlet var contentView: UIView!
#IBOutlet weak var labelCardTag: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
let bundle = Bundle(for: DCCardTagView.self)
bundle.loadNibNamed(self.className, owner: self, options: nil)
addSubview(contentView)
}
}

How to load custom UIView from xib using Swift 2?

The task is to create custom UIView that loads UI from .xib file using Swift. How do I do that?
I tried to do that using the code:
import UIKit
#IBDesignable class CustomView: UIView {
var view: UIView!
#IBOutlet weak var label: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "CustomView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
It runs, but crashes with EXC_BAD_ACCESS and shows me the message:
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
Actually, I need to translate code given here http://qnoid.com/2013/03/20/How-to-implement-a-reusable-UIView.html to Swift 2.0, but I have no idea how to do this.
Try
let yourView = NSBundle.mainBundle().loadNibNamed("youViewNibName", owner: self, options: nil).first as! YourView
Do it in your ViewController class, then you can access the view in required init with coder, where you should call xibSetup().
Is it correct, that your class is called CustomView and you're loading CustomView.xib where the class for the view in xib is CustomView?
If that is so you probably do not understand what you're doing

Resources