How to load xib to UIView subclass, Swift, iOS - ios

I have a .xib file called ContentView that I want to use as the view for a class called ContentView, however I cannot seem to load it.
class ContentView: UIView {
override init() {
super.init(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
}
I'm aware that you can load a xib using the following method but this gives a error when I do so:
var contentViewXib: NSArray = NSBundle.mainBundle().loadNibNamed("ContentView", owner: nil, options: nil)
I have also set the xibs files owner to ContentView and set its Custom Class in interface builder to the class I want to use it with.
Any help is appreciated. Thanks

If you set File's owner to ContentView, then view in your XIB is not ContentView, it is normal UIView that ContentView can retrieve.
In the init method of ContentView, call NSBundle.mainBundle().loadNibNamed() just like you wrote in your question and then type:
self.addSubview(contentViewXib[0])
You will also need to set constraints or autoresizing mask for this new view.
EDIT:
Another solution is to select view directly (not File's Owner) and change its class to ContentView.

Related

What is the purpose of using super.init creating custom view with xib?

I want to understand why we use super.init all the time.
For example,
class HeaderStyle1: UIView {
var subview: UIView! //NİB
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit(){
subview = Bundle.main.loadNibNamed("HeaderStyle1", owner: self, options: nil)?.first as! UIView
subview.frame = bounds
subview.autoresizingMask = [.flexibleHeight, .flexibleWidth]
addSubview(subview)
}
First: When I instantiate
header = HeaderStyle1(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 80))
super.init(frame: frame) instantiates UIView. Why we need this?
class ViewController: UIViewController {
var header: HeaderStyle1!
override func viewDidLoad() {
super.viewDidLoad()
createView() }
func createView() {
//Create Header
header = HeaderStyle1(frame: CGRect(x: 0, y: 0, width: self.view.fr
self.view.addSubview(header)
}
Second: I add header to UIViewController view as subview. Here header is an instance of HeaderStyle1. So I actually add a class to UIViewController view. How does UIViewController view show instance as view? Is it because of super.init or something?
Thank you
self.view.addSubview(header)
First , as every class is a subclass of another You call super.init is done to insure that if you call some Instance Variable / Method of the super class, you'll be able to do so as the super class is successfully initiated
suppose that i sublassed NSArray and in some point in app i want to call
NSArray*er = [myArr mutableCopy];
the copy process will fail if [super init]; failed when i subclassed NSArray
as mutableCopy is a method in NSObject that i ignored it's super init
Second , you actually adding an instance of a UIView (HeaderStyle1) to the current view controller's view (which also an instance of UIView) not class to class , this is a hierarchy made by Apple so developers can add different views to their apps to satisfy certain layout needs and modularize their Design so on for all UIKit components (UILabel,UITextfeild.....) that are pre-designed in IOS frameworks to display common components that make sense in small Mobile devices

How to allow subclasses to use parent class's nib

Say I have a parent view class, that contains at least 1 property:
class BaseView : UIView {
#IBOutlet weak var myLabel: UILabel!
}
This class has a corresponding xib file with an outlet connection made from the xib to the myLabel property.
Now let's say we also have some child classes that inherit from this class:
class ChildView : BaseView {
func setup() {}
}
ChildView has some custom logic but can reuse all of the views from BaseView. It doesn't (or I'd prefer to avoid it having) its own corresponding xib file.
I'd like to be able to do something like this:
let childView = Bundle.main.loadNibNamed(String(describing: BaseView.self), owner: nil, options:nil)?.first as! ChildViewA
but this doesn't work. Neither does:
let childView = ChildView()
Bundle.main.loadNibNamed(String(describing: BaseView.self owner: childView, options: nil)
Is there anyway to allow a child view to inherit from its parent view's xib file in a similar way?
The problem is that the root view in the nib is of type BaseView, so as! ChildViewA fails. Since you don't have access to the NSKeyedUnarchiver that the nib loader uses to unarchive the xib, there is no easy way to substitute your own class during unarchiving.
Here's a workaround.
Do not embed the BaseView itself in the xib. Instead, make the top-level view in the xib be a plain UIView, and set the File's Owner custom class to BaseView. Then delete all of the connections to the top-level view and set them on the File's Owner instead. Also give BaseView a rootViewFromNib outlet, and connect it to the root view.
Then, give BaseView an initializer that loads its nib and adds that rootViewFromNib to itself as a subview, with its frame pinned to the BaseView's own bounds. You can use autoresizing to do it.
In the end, BaseView should look like this:
class BaseView: UIView {
#IBOutlet var myLabel: UILabel!
// other outlets, etc.
#IBOutlet private var rootViewFromNib: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
Bundle(for: BaseView.self).loadNibNamed("BaseView", owner: self, options: nil)
rootViewFromNib.frame = bounds
rootViewFromNib.autoresizingMask = [.flexibleWidth, .flexibleHeight]
rootViewFromNib.translatesAutoresizingMaskIntoConstraints = true
addSubview(rootViewFromNib)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
and BaseView.xib should look like this:

How to add reusable custom views programmatically? (Swift)

I've created a reusable xib file that contains a table and it's being loaded in a TableView.swift file like this:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
Bundle.main.loadNibNamed("TableView", owner: self, options: nil)
}
I'm only mentioning this to clarify that I am not confused about how to load the xib file
I can easily load the reusable view in my RootViewController.swift file by adding a view to the UIViewController and giving that view a custom class like this:
and then creating an outlet for that view like this:
So here is my question:
Why am I not able to simply add the view like this:
let tableViewView = TableView()
When I do, I get an error that I don't totally understand:
You need to override the frame initializer as well.
Assuming your TableView class is a UITableView subclass, it should look something like this:
class TableView: UITableView {
override init(frame: CGRect, style: UITableViewStyle) {
super.init(frame: frame, style: style)
// any additional setup code
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// any additional setup code
}
}
Because you are trying to instantiate the table view programmatically, you need to give it an initializer for the frame, not only an initializer with a coder.

Load custom UIView from xib programmatically

I have created a custom UIView in MySample.xib. I have added the class MyView to the File Owner of xib.
MyView.swift
class MyView: UIView {
#IBOutlet var view: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
NSBundle.mainBundle().loadNibNamed("MySample", owner: self, options: nil)
self.addSubview(self.view)
}
}
I am now loading this MyView from MyController file like this:
MyController.swift
class MyController: UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
view.addSubview(MyView())
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Now to display this view, I am using to following code from another controller's UIButton:
presentViewController(MyController(), animated: true, completion: nil)
This does display the view on screen. But the problem is, it doesn't accept any user interaction. In my custom view, I have a UITableView which does display the data but it doesn't scroll or get tapped due to lack of user interaction.
Any idea what I am doing wrong?
There are some unnecessary things in your example.
I am still not sure what are you trying to do, but if you want to add a custom view from xib to your view controller then:
Create a view in a xib file , you don't need to override init , and you can't init view from xib using the default init UIView() , so please remove init method from your MyView class.
In your xib make sure that your view that you see in the IB is of the class type you want to use (i guess MyView class).
In your view controller init the view like this:
class MyController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Get all views in the xib
let allViewsInXibArray = NSBundle.mainBundle().loadNibNamed("MySample", owner: self, options: nil)
//If you only have one view in the xib and you set it's class to MyView class
let myView = allViewsInXibArray.first as! MyView
//Set wanted position and size (frame)
myView.frame = self.view.bounds
//Add the view
self.view.addSubview(myView)
//TODO: set wanted constraints.
}
}
You don't have to re-instantiate this twice
already if you using the design pattern.
It's so simple. Just write:
class MyController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Get all views in the xib
let view = MyView()
self.view.addSubview(myView)
//TODO: set wanted constraints.
}}
And It will work.
Instead of linking xib File's Owner class to MyView, I have to change the class of root view in xib to MyView. Then based on #Oleg Sherman code, it works perfectly with small changes of adding MyView() as owner to get all it's events, otherwise it will throw an error this class is not key value coding-compliant for the key ****.:
let allViewsInXibArray = NSBundle.mainBundle().loadNibNamed("MySample", owner: MyView(), options: nil)
Using File's Owner class to MyView is only required when you have to use the xib in Storyboard.
Not sure if there is a workaround to use File's Owner class to MyView when programmatically loading xib from custom controller like in my original question.

Add UIView as SuperView subView from its own UView SubClass

Actually I think this one is very simple, and I'm missing something.
I'm creating Subclass of UIView, and instead of adding it as a subView from the ViewController like this :
rateus = RateFrameWork(AppID: "asdasds", BackGroundColor: UIColor.blueColor())
self.addSubView(rateus)
I'm trying adding it from the subclass, this is what I tried so far :
class RateFrameWork: UIView
1) From the super init coder(dosent work)
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
superview?.addSubview(self)
}
2) From the init method(dosent work)
init?(AppID: String!, BackGroundColor: UIColor!)
super.init(frame: CGRect(x: 0 , y: 0, width: UIScreen.mainScreen().bounds.size.width , height:UIScreen.mainScreen().bounds.size.height))
superview?.addSubview(self)
Any suggestions? How can I add it as subview from its own subclass?
You can't do it because this is contradictory to the idea.
A view does not have superview unless it's to be added as subview, and a view does not know that it would be added as a subview under what circumstances and when.
Some special views(e.g. AlertView、ActionView) can be added to the keyWindow but your view not.

Resources