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)
}
}
Related
I have a UIView Class with xib. I try to add it in another ViewControllers as a popover view. I have outlet connections. But when I run the application it crashed and stated
This class is not key value coding-compliant for the key btnAbtUs
I think the problem is should select delegate. I may using wrong way to add this xib. How can I correct it?
Here is my code.
my UIView subclass
class MoreView: UIView {
#IBOutlet var containerView: UIView!
#IBOutlet weak var btnAboutUs: UIButton!
override public func awakeFromNib() {
super.awakeFromNib()
}
override init(frame: CGRect) {
super.init(frame: frame)
loadViewFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadViewFromNib()
}
func loadViewFromNib() {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "MoreView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.insertSubview(view, at: 0)
commitInit()
}
private func commitInit(){
containerView.translatesAutoresizingMaskIntoConstraints = true
self.btnAboutUs.addTarget(self, action: #selector(self.clickAboutUs(_:)), for: .touchUpInside)
}
class func instanceFromNib() -> UIView {
return UINib(nibName: "MoreView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}
#objc func clickAboutUs(_ sender: Any) {
print("tap")
}
}
in UITabBarController
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
let moreView = MoreView.instanceFromNib
if let navigationController = viewController as? UINavigationController,
navigationController.viewControllers.contains(where: { $0 is MoreViewController }) {
moreView().frame.origin.y = 100
self.view.addSubview(moreView())
return false
} else {
moreView().removeFromSuperview()
return true
}
}
Finally I found the issue. This is the right way to add a UIView as a SubView controller of a UIViewController.
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if let navigationController = viewController as? UINavigationController,
navigationController.viewControllers.contains(where: { $0 is MoreViewController }) {
let mySubView : MoreView
mySubView = MoreView(frame: CGRect(x: 0, y: 0, width: 375, height: 667) )
self.view.addSubview(mySubView)
return false
} else {
return true
}
}
You might have copied the XIB and forgot to remove/add a connection with the IBOutlet. Please check.
It indicates that an already connected Interface Builder object is removed/renamed in its owner's source (File's Owner).
You may forgot to remove a connection with the IBOutlet. Please check on on show connection inspector.First click on file inspector of xib then click on show connection inspector. Shown in image.
Remove the broken outlets.
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.
I create a framework with Custom View. When I'm try to load this to simulator, it loads but when there's a bug when load in deferent iPhone simulators.
I set the constraints to 0, but the custom view doesn't load in all view.
framework code:
#IBDesignable
public class SummaryHeaderView: UIView {
/* View */
#IBOutlet public var view: UIView!
public override init(frame: CGRect) {
super.init(frame: frame)
setUpNib()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUpNib()
}
internal func setUpNib() {
view = loadNib()
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(view)
}
internal func loadNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: String(describing: SummaryHeaderView.self), bundle: bundle)
guard let summaryHeaderView = nib.instantiate(withOwner: self, options: nil).first as? UIView else {
return UIView()
}
return summaryHeaderView
}
}
app code:
#IBOutlet weak var myView: UIView!
var summary = SummaryHeaderView()
override func viewDidLoad() {
super.viewDidLoad()
summary = SummaryHeaderView(frame: self.myView.bounds)
myView.addSubview(summary)
}
Result:
One serious problem with your code is this:
override func viewDidLoad() {
super.viewDidLoad()
summary = SummaryHeaderView(frame: self.myView.bounds)
}
You are assuming here that self.myView.bounds is known at the time viewDidLoad runs. That assumption is wrong. viewDidLoad is too soon for that. Therefore your summary header view shows at the wrong size.
A simple solution would be: instead of using absolute frames everywhere, use auto layout constraints everywhere. That way, all your views and subviews will adjust themselves automatically no matter how big the screen turns out to be.
Another way to do this is to wait until the size of the view is known. For example, move your code into viewDidLayoutSubviews. But then you must take extra steps so that you don't add the subview again later, because viewDidLayoutSubviews can be called many times during the app's lifetime.
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)!
}