Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GLKit's -drawRect: is not called during screen rotation

I have GLKit-based app with some simple object displayed.

All works fine, except screen rotation, during which GLKView is not updated (-drawRect: is not called). So during rotation projection matrix is not updated according to dynamically changing screen sizes and object looks badly (stretched).

like image 534
kpower Avatar asked Mar 07 '13 19:03

kpower


2 Answers

This might be a shot in the dark since I don't have any experience with GLKit, however I do have experience with UIView and -drawRect:. Try changing the contentMode of the view in question to redraw:

view.contentMode = UIViewContentModeRedraw;

This will tell the view that it needs to redraw it's contents when it's boundaries change. Otherwise, UIView will simply attempt to scale it's contents (the default for contentMode is UIViewContentModeScaleToFill). The reason for this is that it's a lot easier to scale what's there than to redraw the contents and UIView is designed to be as efficient as possible.

like image 173
Aaron Hayman Avatar answered Nov 15 '22 06:11

Aaron Hayman


That's simply not how UIKit animations work. I sort-of explain how half of it works in this answer, but I'll try to summarize the relevant bits:

  • Everything is a textured rectangle. (There are some exceptions, like perhaps CAShapeLayer, but this is true for the most part.)
  • UIView's properties are linked to CALayer's "model tree" properties. They change instantaneously.
  • Animations work by animating the "presentation tree" properties from the starting value to the current model value.
  • The starting value of the animation is, by default, the previous model value. Specifying UIViewAnimationOptionBeginFromCurrentState makes it use the current presentation value.

There are, of course, a few exceptions (CAShapeLayer seems to be more than a textured rect, UIScrollView does scrolling animations on a timer, UIView transitions are another thing entirely...).

How rotation is supposed to work is that you get a single -setFrame:, everything is laid out (and potentially rerendered), and then the animatable properties are animated. By default, this means things will rerender to the new dimensions but get stretched to fit the old dimensions, and then animate (and unstretch) as the rotation progresses.

That said, GLKView might work differently. If you're using GLKViewController, it might even suspend rendering during the rotation animation. You could try calling -setNeedsDisplay during the rotation, but it won't help much since the frame is already set to its final value.

Probably the easiest way to handle the rotation animation yourself is to force a non-animated relayout to the rotated frame and then do some fudging in the renderer (the black border and status bar animate separately though).

Alternatively, the traditional way is to make your VC portrait-only and handle the device orientation notifications yourself, but this is a big can of worms (you then have to worry about the status bar orientation which determines things like the touch offset and keyboard orientation, and it tends to interacts "interestingly" when transitioning to/from other VCs).

like image 45
tc. Avatar answered Nov 15 '22 08:11

tc.