Анимация в представлении OpenGL ES зависает при перетаскивании UIScrollView на iPhone
У меня есть анимированное прозрачное подпредставление OpenGL ES (модификация шаблона Apple класса EAGLView), которое рисует вращающуюся сферу. Как и в примере с Apple, CADisplayLink используется на устройствах, где они доступны.
На том же экране есть UIScrollView, содержащий кнопки UIB, которые можно выбрать. Когда пользователь прокручивает UIScrollView, анимация моего EAGLView останавливается. Это поведение воспроизводится на iOS Simulator 4.2 и на iPhone OS 3.1.3 на устройстве iPhone 2G.
Любые идеи о том, что нужно сделать, чтобы предотвратить паузу EAGLView, кроме кодирования моего собственного представления прокрутки?
1 ответ
Будь то CADisplayLink
Пожары во время прокрутки зависят от режима, с которым вы добавляете его в цикл выполнения. Вероятно, у вас есть это где-то:
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
UIApplication добавляет режим цикла выполнения, UITrackingRunLoopMode
, для "отслеживания в элементах управления", который включает в себя, когда прокрутка прокрутки. Таким образом, в этот момент runloop выключен из режима по умолчанию и, следовательно, ваша ссылка на дисплей (а также любые таймеры, NSURLConnections
и т. д., добавленные в режиме по умолчанию) не будут срабатывать до восстановления режима по умолчанию.
Быстрое исправление: измените код на:
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
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
}