在iPhone上拖动UIScrollView时,OpenGL ES视图中的动画会冻结

Iva*_*ica 22 iphone opengl-es uiscrollview uikit

我有一个动画透明的OpenGL ES子视图(Apple的模板EAGLView类的修改),它绘制一个旋转的球体.就像Apple的例子一样,CADisplayLink用在可用的设备上.

在同一屏幕上,有一个UIScrollView包含可以选择的UIButtons.当用户滚动UIScrollView时,我的EAGLView的动画会冻结.此行为在iPhone 2G设备上的iOS模拟器4.2和iPhone OS 3.1.3上重现.

除了编写自己的滚动视图之外,还有任何关于如何防止EAGLView暂停的想法?

Tom*_*mmy 57

CADisplayLink滚动期间是否触发取决于将其添加到运行循环的模式.可能你有这个,某个地方:

[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
Run Code Online (Sandbox Code Playgroud)

UIApplication UITrackingRunLoopMode为"跟踪控件" 添加了一个运行循环模式,其中包括滚动视图滚动时.因此,此时runloop将退出默认模式,因此您的显示链接(以及NSURLConnections在默认模式下添加的任何计时器等)将无法触发,直到恢复默认模式.

快速修复:将您的代码更改为:

[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
Run Code Online (Sandbox Code Playgroud)

UITrackingRunLoopMode被认为是常见模式之一.

花费太多时间打断UIKit会导致一些非常糟糕的控制响应,所以你需要小心.它是大规模地偏离主题,但是虽然OpenGL是模态的,因此不是特别的线程友好,你可以使用EAGLSharegroup在单独的线程上进行渲染,然后将其推送到主线程.


(2016)Swift3中的一个例子......

let d = CADisplayLink(target: self, selector: #selector(ThisClassName.updateAlpha))
d.add(to: RunLoop.current, forMode: RunLoopMode.commonModes)


//and then, for example...
func updateAlpha() {
  let a = leader.layer.presentation()?.value(forKey: "opacity") as! CGFloat
  follower.alpha = a
  }
Run Code Online (Sandbox Code Playgroud)

  • 只是一个小小的补充!虽然这很有效,但它仍会触发iOS4设备上的错误,其中UIScrollView从不捕获触摸事件并在滚动模式下冻结.这不会出现在iOS4模拟器中,也不会出现在带有iOS3.1.3的iPhone2G上.解决方案变得非常简单:即使支持displaylink,我也切换到基于NSTimer的代码路径,并且我在NSRunLoopCommonModes中安排了NSTimer. (3认同)