无法使用 iOS 8/9 SDK 使 OpenGL ES 视图适合屏幕

Unable to fit OpenGL ES view to screen with iOS 8/9 SDK

我有一个基于 Apple 的旧 OpenGLES 示例构建的通用横向应用程序,当我在 XCode 6 或 7 中构建时,视图是横向的:

Apple 以前破坏了我的旋转,之前我只是通过使用变换来旋转和缩放我的视图来修复它,效果很好。

使用 XCode 6/7,如果我使用 CGAffineTransformMakeRotation() 旋转图层,则旋转是正确的,但它保留了原始纵横比:

这应该很容易通过缩放来解决,但奇怪的是我无法缩放它以适合屏幕。我可以匹配宽度或高度:

但是无论我使用什么值进行 height/width 缩放,都不可能将高度和宽度都缩放到屏幕上。这是我设置(应该是什么)正确的缩放值时得到的结果:

我已经尝试了很多缩放比例,但出于某种原因,宽度和高度似乎并不完全相互独立。自动布局已关闭,我找不到任何设置约束的地方。我也试过设置视图边界和框架,但它与我使用变换时遇到的奇怪缩放限制完全相同。

如果我旋转 OpenGL 缓冲区的像素尺寸,它会以正确的大小显示,但右侧会被截掉。我也找不到任何方法来解决这个问题:

使视图正确适合的唯一方法是将应用程序的 plist 方向从横向 Left/Right 更改为仅标准纵向。但这会在与其他音乐应用程序交互时产生方向问题,因为我的软件实际上并不是纵向运行的——切换应用程序时方向有时会翻转,而且有一半时间我的应用程序是颠倒的。

首先缩放视图是不合适的,你应该避免。你提供的关于你是如何做你正在做的事情的信息太少了,但我可以想象你使用了自定义设置来创建你自己的帧缓冲区,就像在旧示例中​​一样...

在这种情况下,您必须了解这或多或少是 iOS 类似于创建 FBO 的独特过程。在大多数平台中,帧缓冲区会根据您的视图调整大小,但不会在您的视图中调整。在您的情况下,最简单的解决方法就是重新创建缓冲区。在旋转更改时删除帧和渲染缓冲区,然后重新创建它们。

可能更好的解决方案是创建一个足够大的正方形视图以填满屏幕并将其放置在中央。然后,您的视图应始终正确放置和旋转,但您需要手动设置视口:

- (instancetype)initWithFrame:(CGRect)frame {
    if((self = [super initWithFrame:frame])) {
        CGFloat size = frame.size.width>frame.size.height?frame.size.width:frame.size.height;
        self.glView = [[UIView alloc] initWithFrame:CGRectMake(.0f, .0f, size, size)];
        self.glView.center = CGPointMake(self.frame.size.width*.5f, self.frame.size.height*.5f);
    }
    return self;
}
- (void)viewDidRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation {
    // the view should already have corect size
    [self resetViewport];
}
- (void)resetViewport {
    CGFloat scale = 1.0f; // A scale you use on the layer (if any) when creating the render buffer. These are usually depending on the display (2x, 3x)
    CGFloat xOffset = (self.glView.frame.size.width-self.frame.size.width)*.5f;
    CGFloat yOffset = (self.glView.frame.size.height-self.frame.size.height)*.5f;
    glViewport(xOffset*scale, yOffset*scale, self.frame.size.width*scale, self.frame.size.height*scale);
}

应该做这样的事情。还要记住在缓冲区初始化后重置视口。您也可以考虑为视口值设置动画,以便在设备改变方向时获得漂亮的动画效果。

结果是包含 OpenGL 层的视图实际上没有被正确地框起来。我之前调查过这种可能性并认为框架是正确的,但我仍然不确定为什么我的应用程序之前可以运行或者它如何进入框架设置不正确的状态。但对我有用的解决方案是在其 layoutSubviews() 回调中将 OpenGL 视图的框架和边界与其父视图相匹配。

- (void)layoutSubviews // for UIView containing OpenGL layer
{
    [self remakeFramebuffer];

    self.bounds = self.superview.bounds;
    self.frame = self.superview.frame;
    self.center = self.superview.center;
}