I've created an xib and loaded the nib in my viewDidLayOutSubviews:
I then added the subview:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if (myCustomView == nil) {
myCustomView = Bundle.main.loadNibNamed("Help", owner: self, options: nil)?.first as? HelpView
self.view.addSubview(myCustomView!)
}
}
My constraints are all set up correctly in my xib (toggling between devices look okay), however when I launch the app on a different device the autolayout is not updated. How do I fix this? Thank you!
Edit:
Toggled for iPhone 7, but launching for iPhone 7 Plus
Toggled for iPhone 7 Plus, launching for iPhone 7 Plus
Your constraints may be setup correctly in your nib, but you don't have any constraints when you call self.view.addSubview(myCustomView!), so the frame is just going to be whatever it is in the nib file. You need to constraint myCustomView to self.view. Give it equal width, center X, equal top and a fixed height (or use the intrinsic height) and it should be fine. Make sure you turn off translatesAutoresizingMaskIntoConstraints.
just add this line below
self.view.addSubview(myCustomView!)
myCustomView.translatesAutoresizingMaskIntoConstraints = false;
//Views to add constraints to
let views = Dictionary(dictionaryLiteral: ("myCustomView",myCustomView))
//Horizontal constraints
let horizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|[myCustomView]|", options: nil, metrics: nil, views: views)
self.view.addConstraints(horizontalConstraints)
//Vertical constraints
let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|[myCustomView(SpecifyFixedHeight)]|", options: nil, metrics: nil, views: views)
self.view.addConstraints(verticalConstraints)
Related
I'm trying to build a reusable UIView whose width should equal to its superview in Swift.
Since the size of its superview varies, I think I have to set constraints for it with auto layout.
But I can't figure out how to do it programmatically in Swift.
Here is the code for the reusable subview:
import UIKit
class bottomMenu: UIView {
#IBOutlet var bottomMenu: UIView!
required init(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
NSBundle.mainBundle().loadNibNamed("bottomMenu", owner: self, options: nil)
bottomMenu.backgroundColor = UIColor.redColor()
//How to make the width of the bottom Menu equal to its superview?
self.addSubview(self.bottomMenu)
}
}
Can anyone show me how to make it?
Thanks
You can override didMoveToSuperview() method in your UIView subclass and add the constraints there:
override func didMoveToSuperview() {
super.didMoveToSuperview()
backgroundColor = UIColor.redColor()
let views = ["view" : self];
self.setTranslatesAutoresizingMaskIntoConstraints(false)
self.superview?.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[view]|", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
self.superview?.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
}
Add constraints for element inside. For each element add constraint for top, bottom, left and right. If you have any images that needs to be same size add width and height as well. If you can post the screenshot of the UIView I will add more information and will be able to be more helpful.
Also take a look at http://www.raywenderlich.com/50317/beginning-auto-layout-tutorial-in-ios-7-part-1 if you are new to autolayout.
The following code gives the loaded view the same height and width as the super view. (not sure what you wanted for height)
bottomMenu.setTranslatesAutoresizingMaskIntoConstraints(false)
//Views to add constraints to
let views = Dictionary(dictionaryLiteral: ("bottomMenu",bottomMenu))
// Horizontal constraints
let horizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|[bottomMenu]|", options: nil, metrics: nil, views: views)
self.addConstraints(horizontalConstraints)
// Vertical constraints
let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|[bottomMenu]|", options: nil, metrics: nil, views: views)
self.addConstraints(verticalConstraints)
I'm developing a custom keyboard extension and noticed when I call self.inputView.frame.size.width in either viewDidLoad or viewWillAppear, it returns 0 or an incorrect number. Only in viewDidAppear is it correct. This is a problem because I need to update the size of elements in the keyboard based on the available width and height. Right now I am handling this by detecting the frame size in viewWillLayoutSubviews, which is called several times before it is correct. This works, but the user can see the elements changing size in the keyboard - the frame is not correct until after it has been presented to the user. This is also a problem because I need to update the scroll position once the elements are their correct size, so I'm forced to delay that until viewDidAppear. This isn't a great user experience with things jumping around after it's been presented.
Is there any way I could know the height and width of the keyboard earlier in the life cycle so I can set the size of the elements before they become visible to the user?
I am using a XIB to create the keyboard interface which utilizes Auto Layout. This is how I add it to the keyboard:
let keyboardNib = UINib(nibName: "KeyboardView", bundle: nil)
let keyboardInterface = keyboardNib.instantiateWithOwner(self, options: nil)[0] as! UIView
keyboardInterface.setTranslatesAutoresizingMaskIntoConstraints(false)
self.inputView.addSubview(keyboardInterface)
let verticalConstraints: [NSLayoutConstraint] = NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[keyboardInterface]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["keyboardInterface": keyboardInterface, "view": view]) as! [NSLayoutConstraint]
let horizontalConstraints: [NSLayoutConstraint] = NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[keyboardInterface]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["keyboardInterface": keyboardInterface]) as! [NSLayoutConstraint]
self.inputView.addConstraints(verticalConstraints)
self.inputView.addConstraints(horizontalConstraints)
I recently added a scrollview to my viewcontroller. However, this caused my layout to mess up completely.
Here's an image below.
(I gave the UIScrollView a temporary red background, to display, that it's clearly taking the full screen)
now. I have a bunch of things in this view. But to keep it simple I will focus on the top blue bar, which in my app is called "topBar"
First of, I define it in my class.
var topBar = UIView()
I remove the auto sizing, give it a color and add it to my scrollview.
//----------------- topBar ---------------//
topBar.setTranslatesAutoresizingMaskIntoConstraints(false)
topBar.backgroundColor = UIColor.formulaBlueColor()
self.scrollView.addSubview(topBar)
add it to my viewsDictionary:
var viewsDictionary = [ "topBar":topBar]
add the height to my metricsDictionary:
let metricsDictionary = ["topBarHeight":6]
set the height in a sizing constraint.
//sizing constraints
self.scrollView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"V:[topBar(topBarHeight)]", options: NSLayoutFormatOptions(0), metrics: metricsDictionary, views: viewsDictionary))
And finally the part that doesn't work. I /attempt/ to make it the full width of "scrollView"
// Horizontal Constraints
self.scrollView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"H:|[topBar]|", options: nil, metrics: nil, views: viewsDictionary))
and my vertical constraint to put it at the top.
// Vertical Constraints
self.scrollView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"V:|[topBar]", options: nil, metrics: nil, views: viewsDictionary))
Now as for my scrollview, (the one that's probably causing my layout headaches)
It's set up as follows:
as the very first thing in the class:
let scrollView = UIScrollView(frame: UIScreen.mainScreen().bounds)
first thing in my viewDidLoad()
self.view.addSubview(scrollView)
scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
scrollView.scrollEnabled = true
and lastly my viewDidLayoutSubviews.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.frame = view.bounds
scrollView.contentSize = CGSize(width:2000, height: 5678)
}
^ The width of the contentSize will be changed to the width of the screen (I only want vertical scrolling). But right now that's a minor issue compared to the layout problems I'm having
Any help as to why everything is squeezed together would be greatly appreciated!
I managed to fix it doing the following.
Defining my contentsize in viewDidLayoutSubviews
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.frame = view.bounds
scrollView.contentSize = CGSize(width:self.view.bounds.width, height: 5678)
}
and instead of making the view equal to a scrollview, I had to make it a subview of it.
I also had to make a subview of the scrollview, for all my content to work with constraints properly.
self.view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
contentView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentView)
and all my other objects was made subviews of the "contentView" and not the scrollview.
I have UITextView that I would like to make the same height and width of it's container. It is in a simple UIViewContainer.
I tried doing the following:
override public func viewDidLoad() {
self.edgesForExtendedLayout = .None
resultText.text = result
resultText.frame = view.frame
}
This seems to work for portrait but not landscape.
All I am trying to do is make the UITextView take up all the space of it's container.
If I could find the answer in Objective-C I could easily translate it to Swift. I am just looking for the answer for iOS.
I suggest you to use auto layout
Then click add 4 constraints.
If any warning,
Click Update Frames
Autolayout is your friend - It can be done easily using Interface Builder, or in code:
override public func viewDidLoad() {
super.viewDidLoad()
self.edgesForExtendedLayout = .None
resultText.text = result
// add vertical constraints to pin the view to the superview edge
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0.0-[resultText]-0.0-|", options: nil, metrics: nil, views: ["resultText": resultText]))
// add horizontal constrains to pin the view to the superview edge
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0.0-[resultText]-0.0-|", options: nil, metrics: nil, views: ["resultText": resultText]))
}
I need to create a view with a scroll view and a page control in it, and place 7 views inside scroll view.
To lay out subviews inside the scroll view I use pure Auto layout Approach, that is described here.
So I have my controller with XIB file (I don't use storyboards here) that is pretty simple: it's a UIScrollView and UIPageControl with all constraints set up.
And I have a XIB for a UIView subclass Slide which has 2 UIImageViews and 1 UILabel, and there's also some constraints.
To add some views to UIScrollView I use this code in viewDidLayoutSubviews():
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
var pSlide: Slide?
for var i = 0; i < 7; i++ {
var slide = Slide(frame: self.view.bounds, imageName: "slide-\(i+1)-bg", text: NSLocalizedString("slides_\(i+1)", comment: ""))
slide.setTranslatesAutoresizingMaskIntoConstraints(false)
scrollView.addSubview(slide)
var dict: [NSObject : AnyObject] = ["currentSlide" : slide]
if let previousSlide = pSlide {
dict["previousSlide"] = previousSlide
let constraintsHorizontal = NSLayoutConstraint.constraintsWithVisualFormat("H:[previousSlide][currentSlide]", options: nil, metrics: nil, views: dict)
scrollView.addConstraints(constraintsHorizontal)
let constraintsVertical = NSLayoutConstraint.constraintsWithVisualFormat("V:|[currentSlide]|", options: nil, metrics: nil, views: dict)
scrollView.addConstraints(constraintsVertical)
} else {
let constraintsVertical = NSLayoutConstraint.constraintsWithVisualFormat("V:|[currentSlide]|", options: nil, metrics: nil, views: dict)
scrollView.addConstraints(constraintsVertical)
let constraintsLeft = NSLayoutConstraint.constraintsWithVisualFormat("H:|[currentSlide]", options: nil, metrics: nil, views: dict)
scrollView.addConstraints(constraintsLeft)
}
if i == 6 {
let constraintsRight = NSLayoutConstraint.constraintsWithVisualFormat("H:[currentSlide]|", options: nil, metrics: nil, views: dict)
scrollView.addConstraints(constraintsRight)
}
pSlide = slide
}
pageControl.numberOfPages = numberOfSlides
view.layoutSubviews()
}
In this piece of code I create a Slide instance, and set all necessary constraints to it, according to pure Auto Layout approach.
init() method of the Slide class looks like this:
init(frame: CGRect, imageName: String, text: String) {
super.init(frame: frame)
NSBundle.mainBundle().loadNibNamed("Slide", owner: self, options: nil)
self.addSubview(self.view)
self.view.frame = frame
self.layoutIfNeeded()
println("Frame is \(frame); view.frame is \(self.view.frame)")
backgroundImage.image = UIImage(named: imageName)
textLabel.text = text
}
I hoped that
self.view.frame = frame
self.layoutIfNeeded()
will help me but no. The problem is, on 3.5 inch screen all my UIScrollView subviews have the height of 568, which is the normal height for 4 inch display, but not for 3.5 inch.
I'm checking the height in viewDidAppear(animated:) method. But, in init() method of Slide class the height appears to be ok — 480.
I'm trying to solve it for second day already, and still nothing works. I know that this may be much more simple to implement without using Auto Layout and Interface Builder, but I need to do it with these.
I used UIPageViewController instead of all this mess, and it works just fine.