Friday, 12 December 2014

Random problem with UIView rotation and transforms

I was seeing the weirdest problem on my iOS app with rotation. The problem I have is that you cannot force rotate an iOS screen (although you can on Android). In my case, if the user is viewing a landscape image, I need to rotate it so it is correct, whatever way round the user is holding their phone.

As is the way in the world of iOS, I had to find a workaround and UIView.setTransform looked like the answer. It allows you set a transformation matrix to a UIView so that all content drawn to it is rotated, skewed or scaled (I was only using the rotation part). This should have been fine and appeared to work when I accessed my app directly. However, when I accessed my app via a 3rd-party app (it is a single-sign-on utility), it didn't work, or rather, it appeared to functionally do what I expected (a view in the view inspector was rotated) but it was different than the direct access even though it was the same account, same image and the same code definitely called to transform the window.

It is so hard debugging when you don't even know what might be causing it. The only thing I noticed was the way that the view controller was created when accessing the app directly vs the 3rd-party app. If accessed directly, the following code was being called:

UIStoryboard *storyboard = [self getStoryBoard]; // Relevant one for iOS type
UIViewController *initialViewController = [storyboard instantiateInitialViewController];
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
self.window.rootViewController = initialViewController;
[self.window makeKeyAndVisible];

This worked. When I inspected the view stack, it showed more windows stacked including the navigation controller, layout controller etc. as well as the view controller views themselves. When entering from the 3rd-party app, the code was this:

UIStoryboard *storyboard = [self getStoryBoard]; // Relevant one for iOS type
UIViewController *initialViewController = [storyboard instantiateViewControllerWithIdentifier:@"LoginPointsView"];
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
self.window.rootViewController = initialViewController;
[self.window makeKeyAndVisible];

This didn't work. When I inspected the views, I found that there was only the UIWindow and then the views from the view controller itself, none of the intermediate views. Why this caused a problem was unclear, the windows in both cases seemed to be aligned correctly, the only difference was that the view controller's UIView was 90 degrees rotated with respect to the UIWindow in this broken case. As I mentioned, this seemed more correct since I was setting a 90 degree transform but this made it not work. I modified the broken code to be this instead and it all worked:

UIStoryboard *storyboard = [self getStoryBoard]; // Relevant one for iOS type
UIViewController *initialViewController = [storyboard instantiateInitialViewController];
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
self.window.rootViewController = initialViewController;
[self.window makeKeyAndVisible];
UIViewController *ivc = [storyboard instantiateViewControllerWithIdentifier:@"LoginPointsView"];
[(UINavigationController*)self.window.rootViewController pushViewController:ivc animated:NO];

Just another mysterious reason why iOS is fine for basic apps but really becomes hard when you do anything out of the ordinary.
Post a Comment