Assign controls with view iOS, Swift - swift

i have a problem is there any way to make something like outlet in my custom UIView class. I connect view with class via
class func instanceFromNib() -> UIView {
return UINib(nibName: "AddressView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}
my whole class looks like
class AddressView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
var view = AddressView.instanceFromNib()
self.addSubview(view)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
var view = AddressView.instanceFromNib()
self.addSubview(view)
}
class func instanceFromNib() -> UIView {
return UINib(nibName: "AddressView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}
}

You can connect IBOutlets from Storyboard if AddressView is subclass of UIViewController and you make your xib of class AddressView (selecting AddressView as custom class from the Identity Inspector of your xib File's Owner)

Related

Loading UIView from Bundle only fills screen partially

Hello there.
Using Swift 4, I am attempting to load a Custom UIView with XIB onto a UIViewController.
However, it only seems to fill the screen partially, and I'm not sure why.
I did the following:
The view controller is defined in a UIStoryboard
UIViewController that adds the UIView in the viewDidLoad
The UIView swift file and the XIB are connected via the File Owner property
The XIB file is added into the copy bundle resources
The hot pink background color is set using the Xcode visual editor, its not done in code.
I simulate using the iphone xr, but I get the same issue if I simulate on iPhone 6s
The view controller code is empty, but I've included the relevant part:
// QuestionViewController
class QuestionViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let subview = QuestionView()
self.view.addSubview(subview)
}
}
The UIView is also pretty basic:
class QuestionView: UIView, XibView {
override init(frame: CGRect) {
super.init(frame: frame)
setupXib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupXib()
}
func setupXib() {
guard let v = loadFromXib() else {
return
}
addSubview(v)
}
}
I use a protocol that I found on stackoverflow to load the xib file from bundle. Originally I had a lot of issues even loading the bundle, but fortuently I was able to rectify this issue. Anyway, my XIB protocol file is here:
// XIB protocol file
protocol XibView {
func setupXib()
func constrainView(_ view: UIView)
func loadFromXib() -> UIView?
}
extension XibView where Self: UIView {
func setupXib() {
if let xibView = loadFromXib() {
addSubview(xibView)
constrainView(xibView)
}
}
func constrainView(_ view: UIView) {
view.translatesAutoresizingMaskIntoConstraints = false
addConstraints(
NSLayoutConstraint.constraints(
withVisualFormat: "V:|[view]|",
options: [.alignAllCenterX, .alignAllCenterY],
metrics: nil,
views: ["view": view]
)
)
addConstraints(
NSLayoutConstraint.constraints(
withVisualFormat: "H:|[view]|",
options: [.alignAllCenterX, .alignAllCenterY],
metrics: nil,
views: ["view": view]
)
)
}
func loadFromXib() -> UIView? {
let xibView = UINib(nibName: String(describing: Self.self), bundle: Bundle(for: type(of: self))).instantiate(withOwner: self, options: nil).first as? UIView
return xibView
}
}
--
Question:
Why does the UIView not fill the entire screen or only fill the screen partially and how can I resolve this?
With thanks
Edit:
The storyboard looks for the UIViewController only has a single view with no content.
I think you should take a UIview(0,0,0,0 four constraints) in Your Viewcontroller and then assign it a custom class which is a subclass of UIView and then load the Xib file and it will surely occupy the whole screen
Try this man::----
class QuestionViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let subview = QuestionView()
subview.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.width)
self.view.addSubview(subview)
}
}

Swift load nested xib

I am using the xib approach to view controllers and I'm trying to load another xib inside a xib. Is this possible as every documented method I have tried has failed.
I've tried the following: https://medium.com/#brianclouser/swift-3-creating-a-custom-view-from-a-xib-ecdfe5b3a960
And also using the following:
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
view.prepareForInterfaceBuilder()
}
func setup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: identifier, bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
The problem I'm having is the infinite loop scenario, no doubt called from required init. In both approaches files owner has been set/unset as the custom class is unset/set. I've also cleaned the project as well as removed derived data. Just wondered if this was possible?
Thanks

Loading Nib file as inputAccessoryView

I have a Nib file. Image attached. I would like this Nib file as the inputAccessoryView. Reason being accessoryView doesn't adhere to Safe Area on iphoneX. grrrr!
I have set up my Nib file as per this tutorial...
https://medium.com/code-with-rohit/inputaccessoryview-and-iphonex-7b5547fe98da
How do I correctly get this Nib file inside the inputAccessoryView?
I have my custom Class "AccessoryView" as the File's Owner. From here I struggle.
Any help as always highly appreciated.
UPDATE:
I've removed the File Owner and added the class to the top View.
In my AccessoryView Class I have
override init(frame: CGRect) { // for using CustomView in code
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) { // for using CustomView in IB
super.init(coder: aDecoder)
if self.subviews.count == 0 {
self.commonInit()
}
}
class func instanceFromNib() -> UIView {
return UINib(nibName: "AccessoryView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}
private func commonInit() {
guard let container = accessoryViewContainerView else { return }
container.frame = self.bounds
container.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.addSubview(container)
}
}
But it gave me the below effect:
I then add the view to the inputAccessoryView as such:
override var inputAccessoryView: UIView? {
get {
return AccessoryView.instanceFromNib()
}
}
As you can see it has added the subViews but the constraints are all off.

Could not cast value of type UIView to [CustomView] using Xib

I've seen a number of similar questions, but many aren't up-to-date, and none have fixed my issue.
I have a custom Xib and class, CardView. When I try to instantiate it in code, I get Could not cast value of type 'UIView' to 'CardView'.
Class is as follows:
class CardView: NibView {
#IBOutlet var contentView: UIView!
#IBOutlet weak var wordLabel: UILabel!
#IBOutlet weak var flipButton: UIButton!
#IBOutlet weak var playButton: 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("CardView", owner: self, options: nil)
addSubview(contentView)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
override func awakeFromNib() {
super.awakeFromNib()
}
}
and NibView is a custom superclass and looks like:
class NibView: UIView {
var view: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
// Setup view from .xib file
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Setup view from .xib file
xibSetup()
}
}
private extension NibView {
func xibSetup() {
backgroundColor = UIColor.white
view = loadNib()
// use bounds not frame or it'll be offset
view.frame = bounds
// Adding custom subview on top of our view
addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[childView]|",
options: [],
metrics: nil,
views: ["childView": view]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[childView]|",
options: [],
metrics: nil,
views: ["childView": view]))
}
}
extension UIView {
/** Loads instance from nib with the same name. */
func loadNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nibName = type(of: self).description().components(separatedBy: ".").last!
let nib = UINib(nibName: nibName, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as! UIView
}
}
Here is a screenshot of my file inspector showing that I set the File's Owner custom class to CardView, which seems to be a stumbling block for many
Finally, I try to instantiate the CardView as follows: CardView().loadNib() as! CardView
In case someone still having this problem, I have the same problem and I think we follow same tutorial.
You have called loadNib() in your xibSetup(). I think you don't have to call it again.
So instead of using
let myCardView = CardView().loadNib() as! CardView
I just use
let myCardView = CardView()
In your UIViewController, when you create an instance of your CardView, instead of casting it like CardView().loadNib() as! CardView, you call the function object_setClass(_, _) to avoid that error (from Xcode 9).
So it should be like:
let myCardView = CardView().loadNib
object_setClass(myCardView, CardView.self)
view.addSubview(myCardView)
Old question, but in case anyone's here:
My problem was that the view subclass was fileprivate. IB doesn't like that apparently.
For me loading xib programmatically in this way doesn’t work. I had to remove File owner’s class name and set that to the class name of first view. And then I had to set outlets to the components which I’m going to use.
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
override init(frame: CGRect) {
super.init(frame: frame)
}
Added to custom view class after outlets. For you it's CardView. Then I loaded that view class like
let viewCard = Bundle.main.loadNibNamed("CardView", owner: self, options: nil)?.first as! CardView
view.addSubview(viewCard)

Bad access when loading .xib file

Im having bad access on this line super.init(coder: aDecoder). I've tried many solutions i found online but it does not solves it. Im using Swift2.0
import UIKit
class JobsView: UIView {
// Our custom view from the XIB file
var view: UIView!
func xibSetup() {
view = loadViewFromNib()
// use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle.mainBundle()
let nib = UINib(nibName: "JobsView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
override init(frame: CGRect) {
// 1. setup any properties here
// 2. call super.init(frame:)
super.init(frame: frame)
// 3. Setup view from .xib file
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
// 1. setup any properties here
// 2. call super.init(coder:)
super.init(coder: aDecoder)
// 3. Setup view from .xib file
xibSetup()
}
}
Im calling this Nib from this method
func kolodaViewForCardAtIndex(koloda: KolodaView, index: UInt) -> UIView {
//return UIImageView(image: UIImage(named: "Card_like_\(index + 1)"))
return (NSBundle.mainBundle().loadNibNamed("JobsView",owner: self, options: nil)[0] as? UIView)!
}