I have an iPad app and am drawing the main view with openGL and I want to animate my own change when the device is rotated.
Note that this app only draws occasionally, it is not constantly animating. Also my scene is a (very complex) 2D drawing, not 3D. I just want it to simply rotate around the display center during device orientation change, maintaining correct aspect ratio.
At the moment I just have the following code:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// nothing yet
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
IMMainView *mv = (IMMainView *)self.view;
[mv createRenderbuffer];
[mv drawView];
}
I just re-create the OpenGL render buffer to match the new width and height once the rotation completes.
The default iOS behavior seems to rotate the view but also stretches it weirdly as the aspect ratio changes.
I can animate my drawing parameters to make something better appear during the transition, but I don't understand (1) how to stop iOS animating my layer and (2) how to set up an animation loop from these method calls that matches the iOS animation.
For example, during the animation, are the actual view width and height being changed progressively?
Also a possibly issue is the question of when to re-create the render buffer, because if the OpenGL buffer does not match the iOS view bounds then the pixel aspect ratios are not right and the drawing looks bad.
Any help would be appreciated.
I have spent some time looking into reasonable ways of doing this correctly and have ended up going the simplest route which is just to clear the screen on willRotateToInterfaceOrientation
and then to render the new content in the correct place in didRotateFromInterfaceOrientation
. It just doesn't look so bad and the extra complexity for something better is not worth it IMHO.
Alternatively, while I didn't go for this solution, the best result with animation that I achieved with not too much work was something like this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
IMMainView *mv = (IMMainView *)self.view;
[mv drawBlankScreen];
m_oldviewsize = self.view.bounds.size;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
IMMainView *mv = (IMMainView *)self.view;
CGPoint neworigin = mv.origin;
neworigin.x += 0.5f*(self.view.bounds.size.width - m_oldviewsize.width);
neworigin.y += 0.5f*(self.view.bounds.size.height - m_oldviewsize.height);
mv.origin = neworigin;
[mv createRenderbuffer];
[mv drawView];
}
The change of origin is intended to re-center the post-rotated drawing at the same location it was at before the rotation.
I found that willAnimateToInterfaceOrientation
is called once after the new view bounds have been computed. Therefore I set up the new renderbuffer at that point because the distortion associated with the aspect change is not quite as noticeable as my original case. I also had to clear the screen in willRotateToInterfaceOrientation
because there is a delay during which the distorted version of the original drawing is clearly visible.
The downsides to this are that the clearing of the screen causes a slight flash at the start of the animation, and also the stretching distortion is still present but is converging on the correct appearance, not diverging from the old appearance followed by a jump to the new appearance, so it doesn't look so bad. I suspect that any attempt to actually track the animation aspect ratio changes of the view with updating using my drawing function to continuously maintain the correct appearance would be quite complex to implement and likely to be very vulnerable to Apple changing things in the future.