简体   繁体   中英

Autolayout causes small gaps on rotation

My application uses Auto-Layout to create an interface comprising one 2:1 container (fitting the screen size) with two square boxes inside. An example can be seen below (only the left box is visible):

用户界面

When the device is rotated the code updates the constraints to either position the boxes from left to right (landscape) or top to bottom (portrait). The code works reasonably well, but the interface sometimes ends up like this after rotation:

旋转后的界面

As you can see, the background of the container is seen in the left and bottom corner; it varies in severity (sometimes it's even more visible).

I've set up a small project that exhibits the issue; it comprises a small view hierarchy inside a storyboard where all constraints are removed at build time.

The actual constraints are created / updated inside ViewController.m and DualVideoView.m .

The constraints seem pretty accurate to me, so I'm not sure why these layout issues happen in the first place.

Update

Removing the view finder (orange frame in the above screenshots) resolves the layout issue; it uses proportional width & height (eg width := superview.width * 0.9) to draw an inset square frame. I'm not sure why that should be an issue, though.

Although your vertical constraints are not the issue, I would like to point out that they are missing height constraints for video1/video2:

[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_video1 attribute:NSLayoutAttributeHeight multiplier:1 constant:0]
[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_video2 attribute:NSLayoutAttributeHeight multiplier:1 constant:0]

Your horizontal constraints look good, though, so I took your DualVideoView source code and created a minimal application around it ( source code at codepad.org ) in order to reproduce the problem. Unfortunately the minimal application does not show those gaps that you see, so unless you can provide further details I am reduced to guessing. As usual, the most helpful thing you can do is to show a minimal but complete code example that exhibits the problem - maybe you can start by expanding on the sample app that I linked to above.

The main thing that I can think of is that somewhere along the way a rounding error is creeping in because the video1/video2 views should take up half of the width of their superview.

For instance, what happens if the DualVideoView instance gets an odd width of, say, 1023? Assuming that half points are floor ed, half the width of 1023 is 511 (511.5 floor ed). The total width of video1/video2 becomes 1022, therefore leaving a 1 point gap. There are two problems with this assumption, though:

  1. It does not explain the vertical gap since your vertical constraints do not include anything that might lead to a rounding error.
  2. The assumption is wrong, Auto Layout is not floor ing (nor ceil ing), it is rounding. So half the width of 1023 is 512 (511.5 rounded up), which means that if anything video1/video2 should overlap and there should be no gaps.

Some things that you might check:

  • Can you still see the gaps if you rotate twice by 180° (ie if you rotate back to the original position)? If the gaps disappear, then the problem might not be a rounding error but a faulty positioning calculation that depends on the device/interface orientation.

  • Can you still see the gaps if you test with a Retina display simulator or device? There might be a difference because on Retina displays Auto Layout is rounding differently (it allows .5 values and rounds on .25 steps). If the gaps are still there and you are testing on the simulator, it might be interesting to measure with the Pixie app to see if the gaps are 1 or 2 pixels wide.

  • Does it make a difference if you use constraints that align video1/video2 to the edges instead of to the center of their superview (eg align the top/left edge of video1 to the top/left edge of its superview)?


UPDATE

In the GitHub sample project I tracked down the problem to the constraints that exist in the storyboard for the small white subview of the video1 view. Specifically, the problem is somehow related to the 0.9 multiplier - if you reset the multplier to its default 1.0 and instead use a constant, for instance -20, then all resizing problems magically go away. I say "magically", because I am utterly baffled as to why a multiplier should make such a difference. If I find more time I will take another jab at this, but right now this would be my recommendation: Use a constant value instead of a multiplier.

One other thing that I noticed is that most (but not all) of your constraints express dependencies in reverse. For instance:

[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.videoContainerView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0],

This constraint expresses that center.x of the VC main view (superview) depends on center.x of the video container view (the subview). I find this a strange way to think about the relationship between superview and subview, I usually think about this just the other way round. Admittedly, the Auto Layout equation solver seems to be able to cope with this, but I would still recommend to write constraints in their natural dependency order. If nothing else, it will help other people to better understand your code.


UPDATE 2

A little bit of additional research:

  • The layout issue occurs only in the iPhone simulator, but not in the iPad simulator
  • The layout issue disappears if the proportionally sized view is aligned not with the center but with the top and left edges of its superview (video1)
  • Examining 1) the main view, 2) the video container view, and 3) the video1 view (which contains the white proportionally sized view) with the debugging aid constraintsAffectingLayoutForAxis never reveals any constraint that involves the proportionally sized view - although removing the view, or aligning it differently, has a demonstrable effect on the layout

Especially the last point leads me to believe that this combination of constraints exposes a bug in the Auto Layout engine. I suggest you file a bug report with Apple using something like the minimal example you posted on GitHub.

If you set up the constraints in Interface Builder you'll get warnings on missing/conflicting constraints.

Also you can simulate rotations, different screen sizes and get ride of that ugly code ;)

For this particular case where your ratio and sizes are pretty much fixed I would rather implement layoutSubviews though.


If the subviews are kept square then they don't need any special adjustment or constrain. Also you can mix manual ( layoutSubviews ) with auto layout child subviews if needed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM