Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode 8 UIButtons with constraints not showing up

Everything used to work great until yesterday I updated Xcode to version 8.

If I don't use any constraints, I can see the buttons but when I apply constraint(s) to the buttons they disappear, no matter what or how many constraints (height, vertical spacing, trailing etc...) I apply.

When I tap buttons, they act normal (events are always sent so I assume they are actually located there(?)). I tried changing text color, background color, (even adding a new UIButton) but ended with no luck. I can't see the buttons. When I change the background color of Centered View I can see this change on the app. The weirdest part is when I click Debug View Hierarchy on Xcode to see what is going on, everything looks fine there; I can see all buttons located as I expect.

Constraints Design

Testing the app both on iPhone 5 (iOS 9.3.5) and iPhone 6 (iOS 10).

I am using Swift 2.3, iOS 10 and Xcode 8.

Is this a bug on Xcode 8? How to resolve this issue?

UPDATE:

I just realised same constraint problem occurs on UILabel and UIImageView too. They look fine without constraint but when I add any constraint they disappear.

like image 738
JustWork Avatar asked Sep 15 '16 05:09

JustWork


5 Answers

Solved this by forcing layout before setting any layout-related properties like clipToBounds etc... The tricky part is where and when to call layoutIfNeeded.

In my case, I have an UIButton with horizontal,top,and height constraints. Apparently on Xcode 8, my button's title went suddenly missing. Then weird enough the title appeared after I removed the height constraint. This behaviour indicates an issue probably within the view's layout cycle. I needed to have the height constraint so removing it wasn't really the solution. So I tried to call layoutIfNeeded prior to setting the constraints but no effect.

I generate this button on viewDidLoad on a controller via an NSObject class which handles it. The solution for me was forcing a layoutIfNeeded before calling the method that setUps the button.

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view layoutIfNeeded];
    //editBooking - NSObject class where the button gets configured.
    [_editBooking setUpViews];
}

Related issues: clipsToBounds causes UIImage to not display in iOS10 & XCode 8

Edit:

"I think the (0, 0, 1000, 1000) bound initialization is the new way Xcode instanciates views from IB. Before Xcode8, views were created with their configured size in the xib, then resized according to screen just after. But now, there is no configured size in IB document since the size depends on your device selection (at the bottom of the screen)."

Reference: Since Xcode 8 and iOS10, views are not sized properly on viewDidLayoutSubviews

From Apple release notes:

Sending layoutIfNeeded to a view is not expected to move the view, but in earlier releases, if the view had translatesAutoresizingMaskIntoConstraints set to NO, and if it was being positioned by constraints, layoutIfNeeded would move the view to match the layout engine before sending layout to the subtree. These changes correct this behavior, and the receiver’s position and usually its size won’t be affected by layoutIfNeeded.

Some existing code may be relying on this incorrect behavior that is now corrected. There is no behavior change for binaries linked before iOS 10, but when building on iOS 10 you may need to correct some situations by sending -layoutIfNeeded to a superview of the translatesAutoresizingMaskIntoConstraints view that was the previous receiver, or else positioning and sizing it before (or after, depending on your desired behavior) layoutIfNeeded.

Reference: iOS10 release notes

like image 172
Teffi Avatar answered Nov 10 '22 08:11

Teffi


I just found the solution. Most probably this is a Xcode 8 bug. I also faced this issue.

The solution is to change the Xcode version in the interface builder..

Steps,

  1. Select your .xib file.

  2. Open the Utilities section.

  3. Select "File Inspector"

  4. Under the "Interface Builder Documents" change the Xcode version of "Opens in" to "Xcode 7.x"

I think, this will help you.

like image 44
MacKa Avatar answered Nov 10 '22 08:11

MacKa


I was missing the point of setting UIButton class to my custom class. I checked my custom class and have seen that I set corner radius on awakeFromNib() method. I called layoutIfNeeded() before I set corner radius which was the solution in my case.

like image 2
JustWork Avatar answered Nov 10 '22 08:11

JustWork


I don't know if it's a bug, but I solved it adding self.layoutIfNeeded() on awakeFromNib() method. Just in case, I'm subclassing UIButton...

BUT, if you don't, you can't solve the same problem adding that line of code (at least, you can't at this Xcode version). Using viewDidLayoutSubviews() doesn't work too...

like image 1
Javier Siancas Avatar answered Nov 10 '22 09:11

Javier Siancas


Confirmed this is an issue with XCode 8 currently (As of Oct 19) distributed through App Store. It unnecessarily removes some <rect/> element from the Storyboard/xib files.

None of the layoutIfNeeded workarounds works for me. I ended up to download XCode 8 Beta 3 which fixed this issue.

like image 1
John Wu Avatar answered Nov 10 '22 08:11

John Wu