IOS Landscape Orientation Processing Behind The Scenes

Can someone give me a detailed explanation of why iOS handles landscape orientation the way it does with respect to frame and transformation?

What I'm talking about is the following behavior, displayed by registering the description of the views in various Lifecycle view methods:

viewDidLoad: "UIView: 0x1edb5ba0; frame = (0 0; 568 320); autoresize = W+H; layer = <CALayer: 0x1edb5c50>" viewWillAppear: "UIView: 0x1edb5ba0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x1edb5c50>" viewDidAppear: "UIView: 0x1edb5ba0; frame = (0 0; 320 568); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x1edb5c50>" 

The consequences are subtle, but very intriguing.

For example, I launch my application with the Orientation of the Orientation Interface and the Orientation of the Supported Interface configured as "Landscape (right button of the house)"

Then I show my rootViewController as follows:

 self.viewController = [[MyViewController alloc] initWithNibName:nil bundle:nil]; self.window.rootViewController = self.viewController; 

This .xib has the orientation set to "Landscape" and the frame is set to 0, 0, 568, 320. It displays correctly and I can touch all the points on the screen.

The problem arises when I present subview as follows:

 SomeView *someView = [[SomeView alloc] initWithFrame:self.view.frame]; [self.view addSubview:someView]; 

At this point in time, self.view.frame is reported as (0 0; 320 568), and self.view.transform is reported as transform = [0, 1, -1, 0, 0, 0]. The best random scenario, the end result is that I can only touch the left 320px view that I just displayed, in the worst case, that the layout of the view is locked.

Thanks to various SO questions, I found out that the right way to do this is as follows:

 SomeView *someView = [[SomeView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:someView] 

That I did not find out why, and it is very interesting to me.

What I'm even more curious about is why the view is processed as it is at the time of instantiation and display.

It has been quite a while since I got confused with the landscape application, but for some reason I think the current implementation of this is different from earlier versions of iOS, is that right?

+6
source share
2 answers

According to the apple, by default the application supports both portrait and landscape orientations. When the orientation of the iOS device changes, the system sends a notification to UIDeviceOrientationDidChangeNotification to inform interested parties that this has happened. By default, the UIKit platform listens for this notification and uses it to automatically update the orientation of the interface. This means that, with a few exceptions, you do not need to process this notification at all.

The reason you should give borders instead of a frame is simple. When the application is in the landscape, its width and height change places compared to the portrait view. Thus, this leads to impaired behavior. But when providing borders, it takes into account the orientation of the view and accordingly takes the height and width.

When you have view controllers very close to the top of the view hierarchy (or even at the top), you may find that you get this “swapping” effect of width and height. The permutation usually appears on the frame, but not at the boundaries of the view. This is due to the fact that borders are actually some transformations applied to the frame, and sometimes these transformations include a 90-degree rotation (due to the device being in landscape mode). Please note that the exact time when you check the frame property can also be important. If you check the property after loading the image, but before it appears on the screen, you may get an “incorrect” result.

0
source

Great answer from the prince. I would just like to add a quote from docs regarding the frame property of the UIView :

Warning If the transform property is not an identity transformation, the value of this property is undefined and should therefore be ignored.

The bounds property, on the other hand, is expressed in the view’s own coordinate system, so it never changes, no matter which transform you set.

Update: as for your last paragraph, why do you think this behavior is strange or changed? The only way iOS can rotate your view hierarchy is to change view transforms. Therefore, if you want all your views in different view controllers to be oriented the same way, you should use some kind of navigation view controller or present your controllers in different ways. Thus, each controller will rotate its view in accordance with the same rules, and you do not have to manually manage the transformations between the views.

In the early days, you could see code like this:

 UIViewController *ctrl = ...; [window addSubview.ctrl.view]; 

This was before the window had the rootViewController property, and people tend to abuse it for their own views, which can lead to unexpected results when the device is rotated. If you say that you no longer see this code, this is definitely a change and a change for the better, because this code has been broken. Therefore, people just learned how to write code that works correctly when there are changes in orientation.

If you have a game with all its user interface created by the game engine, you only need one (root) view controller. In this case, you do not need to worry about transformations at all. Just request glView borders and adjust your glViewport and in-game elements accordingly. Since glView will have different borders between different devices, your game will gracefully scale on all of them, unless you make any assumptions about the actual screen size and current orientation of your view.

0
source

Source: https://habr.com/ru/post/943891/


All Articles