UIView created from XIB file is not showing - swift

I have created a xib file in my project which looks like this
I'm initializing it with this code
class MainItem: UIView {
class func instanceFromNib() -> UIView {
let view = UINib(nibName: "MainItem", bundle: nil).instantiate(withOwner: nil, options: nil).first as! UIView
return view
}
}
stackView.addArrangedSubview(MainItem.instanceFromNib())
and I'm adding it to a UIStackView which already has some views like UILabel or UIScrollView. but the added view is not showing when I'm running the app and here is the result
what is the problem?

One possible reason is that you did not specify the height of the view, so the height of it becomes to 0 during the rendering process. There are two ways to do it:
Set the alignment of you stackView to .fillEqually. You can do this because the label has non 0 intrinsic heigh.
stackView.distribution = .fillEqually
Tell iOS how to calculate the height of your view. For example override intrinsicContentSize of your view

Related

Swift, newbie question related to containerView. how to make Storyboard viewcontroller for child the same size as a container view

I've been trying to correctly implement a ContainerView in my practice app after watching and reading various tutorials. I initially tried creating the child by utilizing the storyboard and dragging the ContainerView onto the ViewController in question, and then utilizing the child ViewController that is then automatically created, but I need to have multiple child ViewControllers and I couldn't quite figure that out. I researched some programatic ways to do it and I successfully have it functioning the way I want. The only hiccup being that when I am viewing the child ViewControllers on my storyboard they are full size and do not correlate in size to my ContainerView. So I have to have a bit of trial and error in getting the objects I place in the child to fit in the ContainerView.
Can anyone give me some pointers on how I fix that? I've used the code below. The function runs when a button on the parent ViewController is touched. There are other associated child ViewControllers: child2, child3 that run depending on which button is pushed. I didn't include that extra code below for the sake of being concise.
private lazy var child1: PersonInfoChildView1Controller = {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
var viewController = storyboard.instantiateViewController(withIdentifier: "Child1VC") as! PersonInfoChildView1Controller
viewController.person = self.person
addChild(viewController)
return viewController
}()
//MARK: ADD THE CHILD
private func add(asChildViewController viewController: UIViewController) {
containerView.addSubview(viewController.view)
// Configure Child View
viewController.view.frame = containerView.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Notify Child View Controller
viewController.didMove(toParent: self)
}
Try to set your child view controller constraints relative to the container view.
Edit your add method like this:
private func add(asChildViewController viewController: UIViewController)
{
viewController.view.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(viewController.view)
viewController.view.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
viewController.view.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
viewController.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
viewController.view.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
// Notify Child View Controller
viewController.didMove(toParent: self)
}
Also you can create an extension to UIView class to pin the view to the parent view by just one line code
extension UIView {
func pin(to superview: UIView){
translatesAutoresizingMaskIntoConstraints = false
topAnchor.constraint(equalTo: superview.topAnchor).isActive = true
leadingAnchor.constraint(equalTo: superview.leadingAnchor).isActive = true
trailingAnchor.constraint(equalTo: superview.trailingAnchor).isActive = true
bottomAnchor.constraint(equalTo: superview.bottomAnchor).isActive = true
}
}
put this in a separate swift file with this method you can make the container view same size as the view controller
containerView.addSubview(viewController.view)
viewController.view.pin(containerView)
This will save you a lot of time in the future.

How to programmatically set the constraints of the subViews of a UIPageViewController?

I have contained the subViews of a UIPageViewController within a UIView so that my screen has a partial scrollView container. However, the subViewControllers extend beyond both, the UIView that is supposed to contain the (horizontal/swiping page style) scrollView and the screen of the device.
I have already tried to use autolayout constraints but the subViews still go beyond the device screen.
Here is the UIView that contains the subViews of the UIPVC:
let pagingContainer: UIView = {
let view = UIView()
view.backgroundColor = .white
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
and here is the set up within viewDidLoad():
let pageController = PageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
addChild(pageController)
pageController.didMove(toParent: self)
pagingContainer.addSubview(pageController.view)
In case I haven't articulated properly:
What I wish for to happen is that the bottom half of my screen is a horizontal-page-style swiping scrollView that contains x number of subViewControllers (under UIPVC), and the size of subViewControllers are limited to the size of the UIView(pagingContainer).
I think I might understand what you're asking.
It should be pretty simple, set your left/right/top/bottom constraints for the pageController.view to be equal to the pagingContainer
In my example, I'm using SnapKit, so I set the edges equal to superview (which is the paingContainer).
let pageController = PageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
self.addChild(pageController)
pageController.didMove(toParent: self)
pagingContainer.addSubview(pageController.view)
// I set up constraints with SnapKit (since I mostly use that pod)
pageController.view.snp.makeConstraints({ (make) in
make.edges.equalToSuperview()
})
// But if I remember correctly, you can also set it like so:
pageController.view.translatesAutoresizingMaskIntoConstraints = false
pageController.view.widthAnchor.constraint(equalTo: self.pagingContainer.widthAnchor).isActive = true
pageController.view.heightAnchor.constraint(equalTo: self.pagingContainer.heightAnchor).isActive = true
pageController.view.centerXAnchor.constraint(equalTo: self.pagingContainer.centerXAnchor).isActive = true
Here is a quick gif of what it looks like. Main view controller only has red background and a pagingContainer on the bottom half and inset of 30 on each side (to demonstrate the size of pageController being within the pagingContainer and not overflowing)

how to wrap content a custom view in Swift

I have created a xib file which contains some subviews. I set the appreciate width and height for the subviews.
there is class which inherited UIView. This class name is CustomUIView. Then I set This class as the file owner of that xib file.
Now I want to add this xib file to a view controller in storyboard. so I add a UIView and set its class to CustomUIView.
But I have to set width and height for this view. I set leading and top constraint. but I want the height and width of it be set based on the height and width of the subviews.
How should I do it
You don't have to set width and height anchors for the view , if you already set it inside the xib for every element
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let v = (Bundle.main.loadNibNamed("hhhh", owner: self, options: nil))?[0] as! hhhh;
view.addSubview(v)
v.translatesAutoresizingMaskIntoConstraints = false
v.topAnchor.constraint(equalTo:self.view.topAnchor,constant:30).isActive = true
v.leadingAnchor.constraint(equalTo:self.view.leadingAnchor,constant:30).isActive = true
}
Result

Programmatically adding views to Vertical Stack View breaks constraints of vertical stack view

So I have a vertical stack view in a simple layout. When I add a view through Interface Builder I see the view in the stack view no issues.
When I then add views programmatically to the UIStackView it breaks the constraints and the added views appear at the top of the window. I'm confused as to why it would break the constraints of the stack view.
func buildCats(theJson:JSON){
//self.verticalStack.subviews.forEach({ $0.removeFromSuperview() })
print(theJson)
if let infos = self.swiftyJsonvar["info"].array{
for info in infos{
guard let v = UINib(nibName: "ticketOrderView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as? UIView else { return }
v.translatesAutoresizingMaskIntoConstraints = false
self.verticalStack.addArrangedSubview(v)
}
}
}
The added subviews need constraints, as they have no intrinsic size. Try:
v.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).isActive = true
v.widthAnchor.constraint(greaterThanOrEqualToConstant: 200).isActive = true
Hmmm.... I'm doubting this now... I suspect the issue may be related to adding the views on a background thread. Maybe run the loop on the main thread?
Edit 2: Ah... the problem I'm betting now is related to what you're doing with the view / subviews inside your "ticketOrderView"
For an example, see: https://github.com/DonMag/ScratchPad

slow loading of nib in swift2 by instantiateWithOwner

i try to load a custom uiview from a nib by calling instantiateWithOwner
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "myCustomView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
the view is loading successfully but it long time to load (5 seconds).
when i traced the code i found that the reason of delaying in this line :
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
i removed all autolayout constraints but it still delay in calling
I have the same problem, and I found that it's due to the font from the UILabel or other views need font. Change the font to "System Font" solved the problem.
If you remove all subviews from nib you will notice that the loading time is very fast. Then add subview back one by one to check which view slow the time.