【问题标题】:Unable to fit OpenGL ES view to screen with iOS 8/9 SDK无法使用 iOS 8/9 SDK 使 OpenGL ES 视图适合屏幕
【发布时间】:2015-09-23 06:12:46
【问题描述】:

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

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

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

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

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

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

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

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

【问题讨论】:

    标签: objective-c opengl-es ios8 orientation ios9


    【解决方案1】:

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

    在这种情况下,您必须了解这或多或少是 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);
    }
    

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

    【讨论】:

    • 我的应用程序已经按照您的描述进行了设置,但是您评论中的信息让我发现实际上没有正确设置视图的框架和边界。
    • 很好地找到了那个。我还是有点不喜欢重新创建缓冲区。也许在某些时候,您应该考虑另一种方法,即拥有方形视图并简单地使用视口。正如我所说,制作动画也很容易,而且它完全符合您的需要。
    • 只有当您的应用同时支持纵向和横向方向时,更大的方形视图不是才有用吗?我的只是风景。我实际上可以从 layoutSubviews 中删除“remakeFramebuffer”调用,它仍然可以正常工作和旋转。按照我的设置方式,当方向改变时,视图控制器已经为我设置了旋转动画。以前是自己翻的,现在让系统翻了。
    • 好吧,如果你只有横向,你应该没有问题。您可以使用相同的缓冲区而无需任何缩放或任何其他转换。我猜您的问题仅在于设置视图的框架...
    【解决方案2】:

    最终导致包含 OpenGL 层的视图实际上没有正确地构图。我之前调查过这种可能性,并认为框架是正确的,但我仍然不确定为什么我的应用程序之前可以工作,或者它是如何进入框架设置不正确的状态的。但对我有用的解决方案是在 layoutSubviews() 回调中匹配 OpenGL 视图的框架和边界到它的父视图。

    - (void)layoutSubviews // 用于包含 OpenGL 层的 UIView { [自我重制帧缓冲区]; self.bounds = self.superview.bounds; self.frame = self.superview.frame; self.center = self.superview.center; }

    【讨论】:

      猜你喜欢
      • 2017-03-22
      • 1970-01-01
      • 2015-09-11
      • 1970-01-01
      • 2016-08-09
      • 1970-01-01
      • 1970-01-01
      • 2018-06-29
      • 1970-01-01
      相关资源
      最近更新 更多