【问题标题】:GLKit's -drawRect: is not called during screen rotationGLKit 的 -drawRect: 在屏幕旋转期间不被调用
【发布时间】:2013-02-23 03:53:42
【问题描述】:

我有基于GLKit 的应用程序,其中显示了一些简单的对象。

一切正常,除了屏幕旋转,在此期间GLKView 未更新(-drawRect: 未调用)。因此,在旋转期间,投影矩阵不会根据动态变化的屏幕尺寸进行更新,并且对象看起来很糟糕(拉伸)。

【问题讨论】:

  • 您使用的是着色器还是 GLKBaseEffect?
  • 都试过了:GLKBaseEffect 和我自己的着色器——结果相同。 -drawRect: 将在动画完成后调用 - 因此任何 GL 渲染(我们通常放置在那里)都将暂停到那一刻。
  • 好的。我在想也许 GLKBaseEffect 上的 projectionMatrix 属性有问题。我会考虑的......

标签: ios glkit screen-rotation autorotate glkview


【解决方案1】:

这可能是在黑暗中拍摄,因为我对GLKit 没有任何经验,但我对UIView-drawRect: 有经验。尝试更改相关视图的 contentMode 以重绘:

view.contentMode = UIViewContentModeRedraw;

这将告诉视图当它的边界改变时它需要重绘它的内容。否则,UIView 将简单地尝试缩放其内容(contentMode 的默认值为UIViewContentModeScaleToFill)。这样做的原因是,缩放现有内容比重绘内容要容易得多,UIView 旨在尽可能高效。

【讨论】:

  • 不幸的是,这在 GLKView 的实践中似乎没有任何区别。
【解决方案2】:

这根本不是 UIKit 动画的工作方式。我在某种程度上解释了它的一半是如何在this answer 中工作的,但我会尝试总结相关的部分:

  • 一切都是带纹理的矩形。 (也有一些例外,比如 CAShapeLayer,但大多数情况下都是如此。)
  • UIView 的属性链接到 CALayer 的“模型树”属性。它们瞬间改变
  • 动画的工作原理是将“表示树”属性从起始值设置为当前模型值。
  • 默认情况下,动画的起始值是之前的模型值。指定 UIViewAnimationOptionBeginFromCurrentState 使其使用当前表示值。

当然,也有一些例外(CAShapeLayer 似乎不仅仅是一个带纹理的矩形,UIScrollView 在计时器上滚动动画,UIView 转换完全是另一回事......)。

假定旋转的工作原理是,您得到一个 -setFrame:,所有内容都已布局(并可能重新渲染),然后动画属性被动画化。默认情况下,这意味着事物将重新渲染到新尺寸,但会被拉伸以适应旧尺寸,然后随着旋转的进行设置动画(和取消拉伸)。

也就是说,GLKView 的工作方式可能有所不同。如果您使用GLKViewController,它甚至可能会在旋转动画期间暂停渲染。您可以尝试在旋转过程中调用-setNeedsDisplay,但这无济于事,因为框架已经设置为其最终值。

自己处理旋转动画的最简单方法可能是强制将非动画重新布局到旋转的帧,然后在渲染器中做一些修改(虽然黑色边框和状态栏是分开动画的)。

或者,传统的方法是让你的 VC 只显示纵向并自己处理设备方向通知,但这是一个很大的问题(你必须担心状态栏方向,它决定了诸如触摸偏移之类的事情和键盘方向,并且在与其他 VC 之间转换时,它往往会“有趣”地进行交互)。

【讨论】:

    【解决方案3】:

    首先,确保在应用程序生命周期的早期某个时间点启用设备方向更改。

    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    

    然后,当您的视图被实例化时,注册这样的通知。

    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(deviceOrientationDidChange:) name: UIDeviceOrientationDidChangeNotification object: nil];
    

    然后在你的视图控制器中实现-deviceOrientationDidChange:并调用-setNeedsDisplay

    【讨论】:

    • -...DidChange 将在方向改变发生后被调用。这一次drawRect: 也将被调用(因为我在每次帧更改时按时间和更新矩阵)。但我需要在此过程中应用更改。
    • 我现在明白了。我虽然你说你根本没有得到任何轮换信息。监听并实现视图控制器方法- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration。持续时间将允许您计算过渡期间的动画。
    • 是的,我知道。而且我还可以重新实现视图的-setFrame: - 并且每个动画步骤都会更改视图大小。但我无法响应这些更改 - 我的意思是,我可以更新投影矩阵,但不会应用更新,因为在动画完成之前不会调用 -drawRect:(和相应的 GL 绘图)。
    猜你喜欢
    • 2021-03-31
    • 2011-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    相关资源
    最近更新 更多