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.
4 Answers
Answers 1
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 } Answers 2
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.
Answers 3
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.
Answers 4
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.
0 comments:
Post a Comment