Loading Nib file as inputAccessoryView - swift

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.

Related

Subview Has Size Miscalculated on Storyboard

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.

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

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)

Assign controls with view iOS, 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)

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)!
}