Is setNeedsUpdateContraints() ignoring me? - ios

I have a Storyboard that uses Auto Layout & Size Classes. I've given up trying to get my UIView to use the Aspect Ratio 1:1 constraint to work. It takes over the entire screen rather than just set height = width like a UIImageViewer does.
So I am trying to change the width and height constraints instead. In IB the width constraint is set to 320 and the height constraint is set to 320. Ultimately I will set the width constraint to the width of the device and the height constraint to the width of the device, hopefully getting a square UIView for the camera to display its session.
However, when I set the constants and then setNeedsUpdateContraints, nothing happens. Yes I would prefer not to do it this way, but I would also prefer to get this &^&$^#( thing to work and not spend any more hours fighting it. Setting leading space to 0, trailing space to 0, top space to 0, and aspect ratio 1:1 does not work. Even though I did it with a UIImageView and it does work for that.
#IBOutlet var captureFrame: UIView!
#IBOutlet var viewHeightConstraint: NSLayoutConstraint!
#IBOutlet var viewWidthConstraint: NSLayoutConstraint!
override func viewDidAppear(animated: Bool) {
self.viewWidthConstraint.constant = 100 //100 = temporary
self.viewHeightConstraint.constant = 100 //100 = temporary
captureFrame.setNeedsUpdateConstraints()
captureFrame.layoutIfNeeded()
}
Any idea how to get a square UIView so that the camera can be displayed in it using IB, auto layout, size classes AND not have it zoomed in X2?
Why aren't my constraints adjusting to 100? Why is my UIView still 320 x 320?

Related

how to make buttons in stackview change size depending on screen size (using main.storyboard or code)

I am trying to figure out how to make my three buttons in a stackview have relative sizing and keep the same multiplier spacing on different devices, e.g. the buttons will be bigger if i am on an ipad compared to an iphone. Secondly the spacing between left and right edges of buttons will be bigger on an ipad compared to that of an iphone device. So far I currently have three buttons in a stackview. I have added horizontally and vertical allignment to my stackview. I have played around with adding equal heights and width and changed the multiplier as well as adding constraints to the buttons however it did not get my desired result.
Here is a screenshot of how i'd like my items to be placed on all devices:
UIStackView has only static spacing. You have two options:
Change spacing inside code with viewWillLayoutSubviews. I prefer it over viewDidLayoutSubviews because changes will follow rotation animation. But if your calculations will depend on other subviews(not just self.view), these frames will not be updated yet. You can change constraint.constant like this too.
#IBOutlet var stackView: UIStackView!
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
stackView.spacing = view.bounds.height * 0.05
}
Using only storyboard, you can't add spacing constraint with modifier. But you can add a transparent view which will be your spacer, and apply width/height modifier to it. This can be used both for UIStackView and for plain views.
I prefer adding equal height constraint for all views with same size(like btn1.height = btn2.height, btn1.height = btn3.height), so I can set size with one constraint to all of them(btn1.height = superview.height * 0.1).
Something like this should work for your:
Result:

AutoLayout: UIImageView and Aspect Fit content mode

I'm trying to place an UIImageView in the parent view's center. Image must keep its original aspect ratio and also it shouldn't exceed parent's bounds. So landscape images should be limited by parent's width and portrait images should occupy as much vertical space as needed keeping original ratio.
Sounds like quite a simple task for AutoLayout, right? Here's my setup for UIImageView:
center vertically in parent
center horizontally in parent
imageView.width <= superview.width
imageView.height <= superview.height
I also set contentMode to Aspect Fit. Everything works really great for small images which are smaller than device screen but for some reason my UIImageView takes more space than its underlying UIImage for large images (notice the green background - imageView.backgroundColor = [UIColor greenColor]).
Why is this happening? I am not an AutoLayout expert by my constraints look reasonable to me. If I use smaller images like 200x400 then UIImageView takes exactly 200x400 points on the screen with no extra green areas.
I'd like to add borders and rounded corners which obviously won't work properly in this case.
This is happenning because you've set width and height constraints as <=.
For small images imageView's frame is calculated without any issues and all constraints are satisfied. But when a big image is set, imageView's size is going to be set so that the image fits, but at the same it is limited by the size of the superview (screen size).
If you know aspect ratio for sure, you can set it as a constraint and
you won't see any green background.
Otherwise just leave your
constraints as they are and set background color to clear color. This
way any unoccupied zones will be transparent and any image you set
will take maximum space in at least one dimension.
Edit:
Probably not the best solution, kind of oldschool. You can add strict width and height constraints and calculate them manually using image's aspectRatio:
#IBOutlet weak var heightConstraint: NSLayoutConstraint!
#IBOutlet weak var widthConstraint: NSLayoutConstraint!
func setImage(image: UIImage) {
imageView.image = image
let screenSize = UIScreen.main.bounds.size
let imageAspectRatio = image.size.width / image.size.height
let screenAspectRatio = screenSize.width / screenSize.height
if imageAspectRatio > screenAspectRatio {
widthConstraint.constant = min(image.size.width, screenSize.width)
heightConstraint.constant = widthConstraint.constant / imageAspectRatio
}
else {
heightConstraint.constant = min(image.size.height, screenSize.height)
widthConstraint.constant = heightConstraint.constant * imageAspectRatio
}
view.layoutIfNeeded()
}
Try to check "Clip to Bounds" for imageView in Interface Builder
Clip to Bounds Image View
and you must have a well-defined height and width, not "<="

what is wrong with constraints in my UIImageView and why I cannot stretch the image on my UIViewController?

This is my current situation:
I have a UIViewController with UIImageView on it.
The latter has the following constraints: trailing to superview, leading to superview, top space to top layout guide, width equals 320, height equals 820.
Height and width are connected as outlets to my class and I'm setting them in viewDidLoad:
#IBOutlet weak var imageHeightconstraint: NSLayoutConstraint!
#IBOutlet weak var imageWidthConstraint: NSLayoutConstraint!
#IBOutlet weak var backgroundImage: UIImageView!
override viewDidLoad(){
backgroundImage.af_setImageWithURL(NSURL(string: photoURL)!)
imageHeightconstraint.constant = backgroundImage.image!.size.height
imageWidthConstraint.constant = self.view.frame.size.width
}
Now, my image is this:
it is 480x640px photo. I tried in my storyboard to set the mode to center, scale to fill, aspect fill, aspect fit and top.
For example, this is center:
aspect fit:
aspect fill:
but I don't know how to stretch this image from left to right and keep the aspect ratio, so the whole photo is visible and its left and right edges stick to the left and right edge of the screen.
I thought those two constraints could fix it:
imageHeightconstraint.constant = backgroundImage.image!.size.height
imageWidthConstraint.constant = self.view.frame.size.width
but it does not work. Maybe the problem is that the resolution of the photo is low (480x640), so the height is only that small? Can you give me any hint how could I fix it?
To have the image stick to both sides of screen and maintain the aspect ratio, set these 4 constraints:
Leading Edge of ImageView to Leading Edge of SuperView.
Trailing Edge of ImageView to Trailing Edge of SuperView.
Top Edge of ImageView to Top Layout Guide Bottom.
Set an aspect ratio constraint: ImageView Width equal to ImageView Height with multiplier 480:640. To set this, control-drag diagonally in the ImageView and select Aspect Ratio from the pop-up. Then change the multiplier to 480:640.
Set the content mode for the image to Scale to fill.
You may not be calling setNeedsLayout() and then layoutIfNeeded().
In order for the UI to update, you need to tell the view to update, not just change the constraints.
Either way, if you want the imageView to consistently fill the screen and you shouldn't have a height/width on the ImageView, only hugging the sides. Also make sure those constraints are ignoring margins.
If you want the image to fill the imageView, set the resizing mode to aspectFill, and If you're looking for it to resize until the left/right or top/bottom reaches the edge of the view, aspectFit is what you need.

Finding the center of UIImageView UIImageView.center unexpected results

I have a UIImageView with the following constraints:
Height Equals 135
Trailing Space to: SuperView = 0
Leading Space to: Superview = 0
Top Space to: Top Layout = 0
The width of the UIImageView in Xcode 7.2 Size Inspector = 600.
In my UIViewController have an outlet to the UIImageView:
#IBOutlet weak var heroImageView: UIImageView!
In viewDidLoad the value of heroImagveView.center = (300.0, 67.5)
However this not the actual center of the image, 300 is way to the right of the UIImageView in an iPhone 5 simulator. Something more like (x: 160.0, y: 67.5) is center, though x is not exact.
In Xcode 7.2 the default width for all my UIViewControllers is 600 pixels, I understand that will not be the runtime rendering width across different Apple devices, but why doesn't UIImageView.center understand this?
How to I get the actual runtime center of a UIImageView?
At viewDidLoad, your heroImageView has a width of 600. Since the leading space to the superview is 0, the x position will be 0. Hence, the center is at 300.
You need to remove the trailing and leading constraints and replace them with a 'center horizontally', and a width constraint.

Resize image to iOS device background

I would like to rescale my image to fit the width of an iOS screen. The following is the code that I used.
#IBOutlet var bgImageView: UIImageView
override func viewDidLoad() {
super.viewDidLoad()
bgImageView.contentMode = UIViewContentMode.ScaleAspectFit;
bgImageView.frame.size.width = UIScreen.mainScreen().bounds.width;
}
This solution however seems to be causing thread problems. What's wrong here?
You can set your image view constrains as follows - its width should be equal to your super view width, centerX and centerY are the same as super's. And height not an equal constraint, but lessThanOrEqual to super's height.
And yes, it is useless to set frame manually while using auto layout constraints

Resources