Вопрос по ios – Как вызвать scrollViewDidScroll: так же, как UIScrollView, но во время пользовательской анимации?

6

У меня есть очень большой горизонтально прокручиваемый UIScrollView, который повторно использует свои подпредставления (перемещает и обновляет их, когда они находятся вне видимой области, подобно тому, как UITableView повторно использует ячейки). Это зависит от scrollViewDidScroll: делегат вызова, который дает мне фактический contentOffset, и здесь я решаю, когда повторно использовать конкретное подпредставление. Все идет нормально.

Иногда мне нужно изменить contentOffset программно, но с пользовательской анимацией (инерция и возврат к конечной позиции). Я могу сделать это довольно легко, используя базовую анимацию.

The problem is, that during custom animation scrollViewDidScroll: delegate method is not called -> I must do it manually so that subviews reusing works. Я пытался звонить с таймером срабатывания каждые 0,02 сек. Теперь есть две проблемы:

I must get UIScrollView contentOffset using [[_scrollView.layer presentationLayer] bounds].origin.x because during animation normal _scrollView.contentOffset does not change.

However info from presentationLayer is not sufficient for exact syncing - sometimes it is bit late.

problem is when the new contentOffset is far from current position. It looks like built-in UIScrollView animation is CAKeyframeAnimation, and scrollViewDidScroll should is called on key frames positions. But I am not able to get these.

If I rely on timer which is not synced with key frames, views are reused on wrong places and I can not see them at all during animation.

Can anyone shed some light on how and when exactly UIScrollView calls scrollViewDidScroll during setContentOffset:X animated:YES? Is it possible to reproduce it without breaking appstore rules?

Ваш Ответ

1   ответ
4

NSTimer с задержкой в 0,02 секунды - это не то, для чего предназначены таймеры. Попробуйте использоватьCADisplayLink, он срабатывает один раз за кадр.

В вашем методе обратного вызова вы можете - если ваша пользовательская анимация запущена - запустить собственный физический код и вызвать -setContentOffset: animated: соответственно. Это даже позволяет вам экспоненциально ослабить то, что CA не позволит вам.

Большое спасибо, теперь синхронизация стала намного лучше. Но все же есть проблема: при прокрутке на большие расстояния повторное использование вида не улавливает скорость прокрутки. То же самое происходит, когда прокрутка по событию касания (пользователь прокручивает) очень быстро. Как только я перестаю использовать презентационный слой для отслеживания положения, пользовательская прокрутка, даже самый быстрый щелчок, возвращается назад. Таким образом, кажется, что просить уровень представления как-то медленно. Есть ли способ заставить UIScrollView обновить contentOffset во время прокрутки, как поведение по умолчанию? Это может ускорить процесс. Vilém Kurz
Извините, должен был сказать вам, что: в вашемCADisplayLink обратный вызов-setNeedsLayout или любой другой метод, в котором вы выполняете повторное использование кода. Christian Schnorr
Решением является вызов setContentOffset: X в обратном вызове CADisplayLink. Смещение X - это результат времени, введенного в вашу функцию анимации. Каждый setContentOffset вызывает метод scrollViewDidScroll: делегат в идеальной синхронизации с частотой кадров дисплея. Именно так UIScrollView работает под капотом. Большое спасибо Jenox за указание верного направления. Vilém Kurz
Да, я вызываю scrollViewDidScroll: в обратном вызове. Завтра я постараюсь описать инструменты, чтобы найти проблему с производительностью. Вы выполняете повторное использование в setNeedsLayout? Vilém Kurz
Ага. Можете ли вы написать мне (см. Мой профиль), когда у вас все еще есть проблемы, чтобы мы не могли продолжить обсуждение здесь на SO? Christian Schnorr

Похожие вопросы