Reputation: 17527
I would like to turn off auto layout for a while and handle the size and placement of a UIView using its bounds
, center
, and transformation
.
I have a very simple 'Single View Application' example. My app has a view controller hosting the main view. In that view are two buttons, and another view (with its background set to pink) which in turn contains an image view (set to aspect fit):
I've distilled my problem into a very simple UIViewController:
@IBOutlet weak var imageHolderView: UIView!
@IBOutlet weak var imageView: UIImageView!
@IBAction func loadImageButtonClicked(sender: AnyObject) {
let url = NSURL(string: "https://c2.staticflickr.com/4/3909/15110089915_21a12eba6a_k.jpg")
let data = NSData(contentsOfURL: url!)
self.imageView.image = UIImage(data: data!)
}
@IBAction func clearConstraintsButtonClicked(sender: AnyObject) {
let bounds:CGRect = self.imageHolderView.bounds
let center:CGPoint = self.imageHolderView.center
NSLayoutConstraint.deactivateConstraints(self.imageHolderView.constraints)
self.imageHolderView.bounds = bounds
self.imageHolderView.center = center
}
N.B. I'm trying to understand this within a more complex project, the example here is just to demonstrate the problem.
When I run the project the image has no source and so the pink UIView (imageHolderView
) takes up much of the screen as expected:
When I click the load image button the controller loads the image from the web into the UIImageView. Because the constraints are all still in place Auto Layout ensures that the picture is aspect-fitted in to the UIImageView constrained to its super view imageHolderView
:
If I now clear the constraints I expect to see no difference because the constraints set by Auto Layout are immediately replaced in code by the same values. But that's not what I see:
How do I grab the bounds and center of a UIView as set by Auto Layout, turn off Auto Layout for the UIView, and then re-establish the bounds and center from my own swift code?
Looking in the debugger the bounds on the UIView imageHolderView
are correct, and the constraints on the UIImageView imageView
are almost (*) still in place (which I'd hope would constrain the UIImageView to fit inside the UIView), but the bounds on the UIImageView have grown to accommodate the full sized image. Why?
(In the more complex app I then go on to resize, rotate, and translate the view with transformations. Apple's documentation states that "if the transform property contains a non-identity transform, the value of the frame property is undefined and should not be modified. In that case, you can reposition the view using the center property and adjust the size using the bounds property instead." The sample code does not use transformations, but as I say my real code does; I think that precludes me from setting the frame.)
(*) I say almost, because there are four constraints on the UIImageView, but in the debugger the count is two.
Upvotes: 1
Views: 2184
Reputation: 130072
There are several things you are forgetting.
First of all, in:
NSLayoutConstraint.deactivateConstraints(self.imageHolderView.constraints)
make sure that you are not deactivating constraints that you need. E.g. if you have a width or height constraint on imageHolderView
, you would deactivate it using this call.
In:
let bounds:CGRect = self.imageHolderView.bounds
let center:CGPoint = self.imageHolderView.center
NSLayoutConstraint.deactivateConstraints(self.imageHolderView.constraints)
self.imageHolderView.bounds = bounds
self.imageHolderView.center = center
You are getting the bounds
and center
of imageHolderView
and then you are trying to assign them back to imageHolderView
. That's wrong because you are deactivating the constraints that set the position for imageView
. You don't have to change the position of self.imageHolderView
because the constraints for it are saved in its superview. On the other hand, self.imageView
has probably all constraints deactivated, so you should be setting its position:
self.imageView.bounds = bounds
self.imageView.center = center
The center
settings is wrong because imageHolderView.center
is specified in the coordinate system of its superview. You should calculate the center manually from bounds
.
self.imageView.center = CGPointMake(bounds.size.width / 2, bounds.size.height / 2)
However, the biggest problem is probably the fact, that bounds
and center
(or frame
) are ignored by default in any view that is created from storyboard/xib with autolayout enabled.
You will have to manually set imageView.translatesAutoresizingMaskIntoConstraints
to true
. Otherwise frame
will be ignored by layout manager.
Upvotes: 3
Reputation: 4825
Since you are clearing contains of the view, it will remove vertical and horizontal hugging constraints of the its subviews. You can fix this by customising your holder we as,
class CustomHolderView: UIView {
@IBOutlet weak var imageView: UIImageView!
override func layoutSubviews() {
super.layoutSubviews()
self.imageView.frame = self.bounds
}
}
Inside holder views layoutSubviews method you should set the frame for your image view.
Upvotes: 2
Reputation: 6691
don't set the bounds, instead set the frame. try this:
@IBAction func clearConstraintsButtonClicked(sender: AnyObject) {
let frame = self.imageHolderView.frame
NSLayoutConstraint.deactivateConstraints(self.imageHolderView.constraints)
self.imageHolderView. frame = frame
}
Upvotes: 2
Reputation: 1915
UIImageView
automatically adds constraints based on its resizing mask and its contentMode. Try to set its contentMode to AspectFit
or AspectFill
and manipulate its frame
instead of its bounds
.
Upvotes: 1