I have the below issue:
This happens on certain screen sizes only. This view is in a nib linked to a separate file listed here:
import Foundation
import UIKit
class FooterActionView : UIView {
#IBOutlet weak var actionButton: UIButton!
let nibName = "FooterActionView"
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
guard let view = loadViewFromNib() else { return }
view.frame = self.bounds
self.addSubview(view)
}
func loadViewFromNib() -> UIView? {
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}
I have confirmed that the constraints on the storyboard are completely correct (and wouldn't result in this miscalculation of the view width).
This view is subclassed from another view controller as follows:
Where can I look to see what's causing this? (Again I'm fairly certain it's not the constraints). I tried googling this but couldn't find anything that seemed to explain it. Any help is greatly appreciated.
You are saying
view.frame = self.bounds
at a time when we do not yet know what self.bounds is. Then the constraints kick in and the bounds of self.bounds change. But the frame of view.frame doesn’t.
A simple solution would be to give your view the ability to resize itself when self.bounds changes:
view.frame = self.bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
Or you could wait until layoutSubviews to set view.frame.
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
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)
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)
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)!
}