GLKit的-drawRect:我有GLKit并显示一些简单的基于对象的应用程序是不是屏幕旋转

问题描述:

期间调用。GLKit的-drawRect:我有<code>GLKit</code>并显示一些简单的基于对象的应用程序是不是屏幕旋转

所有工作正常,除了屏幕旋转,在此期间GLKView未更新(未调用-drawRect:)。所以在旋转投影过程中,矩阵不会根据动态变化的屏幕尺寸进行更新,而且对象看起来不好(拉伸)。

+0

你使用着色器还是GLKBaseEffect? – 2013-03-11 19:32:50

+0

尝试了两个:'GLKBaseEffect'和我自己的着色器 - 结果相同。 '-drawRect:'将在动画完成后调用 - 所以任何GL渲染(我们通常在那里放置)将暂时停止。 – kpower 2013-03-12 07:15:11

+1

好的。我在想,也许GLKBaseEffect上的projectionMatrix属性是错误的。我会想一想... – 2013-03-12 10:56:24

这根本不是如何UIKit的动画工作。我有点解释它的一半工作在this answer,但我会尝试总结相关位:

  • 一切都是带纹理的矩形。 (有一些例外,比如也许CAShapeLayer,但这是大部分真实。)
  • UIView的属性链接到的CALayer的‘模型树’的属性。他们瞬间改变。通过动画从起始值“表示树”属性当前模型值
  • 动画作品。
  • 动画的起始值是,默认情况下,以前的型号值。指定UIViewAnimationOptionBeginFromCurrentState使其使用当前的表示值。

有,当然有少数例外(CAShapeLayer似乎比一个纹理RECT多,UIScrollView没有一个计时器滚动动画,UIView的转换是另一回事完全...)。

旋转如何应该工作是,你得到一个-setFrame:,一切都奠定了(并且可能重新呈现),然后将动画属性动画。默认情况下,这意味着事物将重新渲染到新尺寸,但会拉伸以适应旧尺寸,然后在旋转过程中进行动画(和非拉伸)。

也就是说,GLKView可能会有所不同。如果您使用的是GLKViewController,它甚至可能会在旋转动画中暂停渲染。你可以尝试在旋转过程中调用-setNeedsDisplay,但由于框架已经设置为最终值,所以它不会有太大的帮助。

自己处理旋转动画最简单的方法是强制非动画重新布局到旋转的框架,然后在渲染器中进行一些欺骗(黑色边框和状态栏单独制作动画)。

或者,传统的方法是让自己的VC仅限肖像,并自己处理设备方向通知,但这是一大堆蠕虫(然后您必须担心状态栏的方向,它决定了触摸等事情偏移和键盘方向,并且当转换到其他VC时/从其他VC倾向于“有趣地”交互)。

首先,确保在某些时候在你的应用程序生命周期的早期,使设备方向的变化。

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 

那么当你的看法被实例化寄存器像这样的通知。

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

然后在您的视图控制器实现-deviceOrientationDidChange:,并呼吁-setNeedsDisplay

+0

'-... DidChange'将在方向更改发生后调用。这次'drawRect:'也会被调用(因为我在每次更改帧时都更新矩阵)。但我需要在此过程中应用更改。 – kpower 2013-03-11 09:51:53

+0

我现在看到。我虽然说你没有收到轮换信息。监听并实现视图控制器方法' - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration'。持续时间将允许您在转换过程中计算您的动画。 – 2013-03-11 15:23:38

+1

是的,我知道。我也可以重新实现视图的'-setFrame:',并且每个动画步骤都会改变视图大小。但我无法回应这种变化 - 我的意思是,我可以更新投影矩阵,但更新不会被应用,因为'-drawRect:'(和相应的GL图)不会被调用,直到动画结束。 – kpower 2013-03-12 07:12:28

这可能是一个在黑暗中拍摄,因为我没有任何经验GLKit,然而,我有经验UIView-drawRect:。试着改变视图的contentMode问题重绘:

view.contentMode = UIViewContentModeRedraw;

这将告诉它需要重新绘制它的内容时,它的边界改变视图。否则,UIView将简单地尝试缩放它的内容(contentMode的默认值为UIViewContentModeScaleToFill)。其原因在于,缩放内容比重画内容容易得多,并且UIView被设计为尽可能高效。

+0

不幸的是,这在GLKView的实践中似乎没有任何区别。 – pmdj 2015-11-21 16:25:09