So after compiling an app on XCode 6, I noticed a strange bug that happens only when running on iOS 8:
The UITableView
takes the wrong inner dimensions after updating its frame.
Now I'll try to explain the exact situation:
We have a UITableView
rotated on its side, which basically makes a horizontal UITableView
. It happens through tableView.transform = CGAffineTransformMakeRotation(-M_PI / 2);
.
Now after setting the transform, and then settings its frame - everything is fine.
But of course the system in most cases sends the parent another frame change because it needs to set the parent to the real sizes and not the XIB sizes or any initialization size. In that moment - when I relayout the subviews, including the table view - everything goes wrong.
Actually the frame of the table view is simply set to the bounds
of the containing view, but then the inner scrollview (In iOS 8 the UITableView
has another UIScrollView
inside it, called UITableViewWrapperView
. As UITableView
is a UIScrollView
by itself, I can't figure out why they needed another one...) takes a "height" which equals the parent width. And "height" is actually the width
property, only rotated.
Now we can easily estimate the they have a bug with relating the width of the inner UIScrollView
to the actual width of the parent UITableView
, which could possibly be by reading the .frame.size.width
instead of the .bounds.size.width
.
But the strange thing is that when investigating the frame of the subviews of the UITableView
- it seems that they are all good! So it must be a rendering problem somewhere.
So we are left with a horizontal table which has a blank gap on top, because the "height" of the cells is 320 instead of 568, while the "width" of the cells is fine, set to 320.
I'll be very happy to hear from other people experiencing this problem (Or from Apple), but I have finally found a solution and posting it here with the question, for future reference for me and for others.
This appears to be a new problem with iOS8. When you want to rotate an object it no longer appears to rotate around the upper left corner of the object's frame.
Apple docs for iOS8 state that "an object is rotated about it's center point". So when a vertical UITableView is rotated 90 degrees, it may disappear from view because the center point may be off the visible area. In order to make the table appear as if it was rotated about the upper left corner of the table, you must now also translate the frame by an amount equal to the difference between the frame width and frame height.
It's important to note you need to concatenate the transforms in order to get the desired result, like the following:
First create a 90 degree rotation transform:
Then create a translation amount variable equal to the difference between table width and height:
Then concatenate the original rotation transform with the translation:
When done, you can now transform your tableView as follows:
This will have the effect of both rotating and translating your tableView such that it now appears to have been rotated around the upper left corner of the tableView instead of about the center point.
So the change that made it behave, was instead of doing this:
I have reset the transform, set the frame to the bounds which the UITableView would expect locally after the transform, and then set the transform and set the correct frame. This is a bit confusing, but here it goes: