1

I'm working on a nice screen rotation animation in my iOS app. When the screen's size changes, I update the (Metal) model inside it accordingly.

The problem is that I have visual content "jumps" due to the buggy info from the VC's lifecycle events.
I'm not using AutoLayout, but the visual results are the same for both Auto and Manual Layout - only the code differs.

An example: on my iPhone XR in the

    portrait mode: ViewSize = 414x986, SafeAreaInsets = 92, 0, 34, 0
    landscape mode: ViewSize = 800x414, SafeAreaInsets = 44, 0, 21, 0

The values are so strange because it's Photos Extension :)

Now, when the screen is rotated from Portrait to Landscape, it's not done in one transaction, but in multiple steps:

Events log:
1. ViewDidLayoutSubviews: {{0, 0}, {414, 896}} + {92, 0, 34, 0} -> {{0, 0}, {414, 896}} + {92, 0, 34, 0}
2. SafeAreaInsetsDidChange: {{0, 0}, {414, 896}} + {92, 48, 34, 0}
3. ViewDidLayoutSubviews:  {{0, 0}, {414, 896}} + {92, 0, 34, 0} -> {{0, 0}, {414, 896}} + {92, 48, 34, 0}
4. SafeAreaInsetsDidChange: {{0, 0}, {414, 896}} + {44, 0, 21, 0}
5. ViewDidLayoutSubviews:  {{0, 0}, {414, 896}} + {92, 48, 34, 0} -> {{0, 0}, {414, 896}} + {44, 0, 21, 0}
6. ViewWillTransitionToSize
7. ViewDidLayoutSubviews: {{0, 0}, {414, 896}} + {44, 0, 21, 0} -> {{0, 0}, {800, 414}} + {44, 0, 21, 0}
 
Meaning:
1 = view frame + insets for Portrait orientation (before rotation)
2 = incorrect info: `{92, 48, 34, 0}` is invalid insets, valid ones are {92, 0, 34, 0} in Portrait and {44, 0, 21, 0} in Landscape
3 = incorrect info, see 2
4 = correct insets arrived for Lanscape, but ViewSize is still Portrait
5 = incorrect pair ViewSize + SafeAreaInsets, see 4
6 = ViewWillTransitionToSize event arrived, why so late?
7 = finall correct pair ViewSize + SafeAreaInsets

So the question is:

  1. how can we know that in SafeAreaInsetsDidChange only one of the inset side changed, and more sides are about to change?
  2. how can we know that in SafeAreaIViewDidLayoutSubviews SafeAreaInsets are for the new orientation, and ViewSize is still for the old orientation?

I guess it's not possible to get this info from UIKit, but still try :)

olha
  • 2,132
  • 1
  • 18
  • 39
  • What information are you updating in your Metal model given the information you provided about the bounds and safe area insets values in callbacks? – Eugene Dudnyk Jun 29 '21 at 22:24
  • @EugeneDudnyk I'm re-rendering the textures at the same shift in `CAMetalLayer`. CALayer's view frame origin is jumping due to SafeAreaInsets jumps – olha Jun 30 '21 at 08:44
  • Because this jumping does not happen in system views, I'm wondering if you tried to wrap CAMetalLayer into custom UIView by overriding `+layerClass` and then use auto layout to constrain the custom UIView to safe area insets layout guide. When all layout calculation happens, app will trigger animation on CAMetalLayer.presentationLayer which will receive different bounds on each animation frame. In the `display` method of CAMetalLayer you can read the layer's bounds resolved by the layout, and resize the textures accordingly if necessary. – Eugene Dudnyk Jun 30 '21 at 10:39
  • @EugeneDudnyk Thank you for the so detailed advice, but I don't plan to use AutoLayout. So the question is not about how to update my model, but rather how to gather more info about SafeAreaInsets correctness. – olha Jun 30 '21 at 10:46
  • 1
    Cool, so, my point about autolayout was that you won't have to track all those callbacks. Regarding your question about correctness - try the second part of my comment related to `presentationLayer` and `display` method. – Eugene Dudnyk Jun 30 '21 at 18:57

0 Answers0