Uiscrollview contentoffset не обновляется при изменении

Обнаружена странная проблема, связанная с изменением свойства смещения содержимого представления прокрутки.

У меня есть CADisplayLink, который вызывает метод каждый кадр. Этот метод вычисляет, насколько необходимо настроить смещение содержимого, чтобы получить эффект типа автоматической прокрутки.

@objc private func tick() {

    let fps = 1 / (displayLink.targetTimestamp - displayLink.timestamp)

    let relativeAutoscrollAmount = autoscrollAmount / CGFloat(fps)

    scrollView.contentOffset.x += relativeAutoscrollAmount
}

autoscrollAmount - это свойство CGFloat, которое представляет, на сколько пикселей перемещать каждую секунду. На экране с частотой 60 Гц, таком как iPhone, это будет означать сдвиг на 5/60 при каждом вызове этого метода, если это свойство равно 5. Однако смещение содержимого на самом деле никогда не меняется! Либо визуально, либо по памяти, я могу сломать и осмотреть его в любой момент, и он всегда 0!

Обратите внимание: если я каждый раз настраиваю его на 1 или больше, он работает нормально. Однако анимация делает это далеко не так быстро.

Есть предположения?

РЕДАКТИРОВАТЬ: Очевидно, что вы не можете настроить меньше, чем на пиксель за раз, но когда я делал это ранее с константой ограничения, система просто рассчитывала, как с этим бороться. (Я предполагаю, перемещая только каждые несколько тиков).

0
0
383
1

Ответы 1

Я считаю, что у меня есть ответ или, по крайней мере, объяснение, основанное на теории, подкрепленной некоторыми довольно хорошими доказательствами. Вот так...

В вопросе я привел пример 5/60, где 5 - это количество пикселей, перемещаемых в секунду, а 60 - это частота обновления моего экрана. Это получается примерно 0,083, что, как я уже сказал, не привело к обновлению contentOffset.

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

После долгих проб и ошибок я нашел это значение. Это 0,167. В моей голове это не имело абсолютно никакого значения; но, очевидно, что-то должно было быть, поэтому я начал манипулировать этим различными способами, чтобы попытаться наблюдать какую-то закономерность.

Вскоре выяснилось, что 0.167 * 6 == 1, хотя и интересное наблюдение, снова не имеет большого значения. Пока вы не заметите, что частота обновления дисплея на моем iPhone X, с которым я тестировал, составляет 60 Гц, 10 раз 6. На данный момент я все еще вслепую колю в темноте, но это было, по крайней мере, зацепкой, которую я мог бы немного изучить.

Исходя из этого, я предположил, что система оценивает изменения положения слоев каждые 6 мс или, что более реалистично, 10 раз за цикл отображения. Это поддерживает поведение, которое я наблюдаю, поскольку если значение перемещения слишком мало (IE оно не может быть представлено в этой теории 10 раз за цикл отображения), оно просто игнорируется.

Это довольно смелое предположение, поэтому я решил посмотреть, смогу ли я собрать доказательства в поддержку теории. Я запустил свой iPad pro с дисплеем 120 Гц (в отличие от дисплея с частотой 60 Гц на моем iPhone X), чтобы посмотреть, есть ли тенденция. Конечно, было. Минимальное значение, чтобы увидеть движение, было теперь половина того, что было на экране 60 Гц. Учитывая большую частоту обновления (фактически вдвое) и исходное предположение о 10 обновлениях на цикл экрана, теперь я, как и раньше, вижу 20 обновлений на цикл экрана, каждые 6 мс. Здесь определенно есть отношения.

Теперь я хотел бы подчеркнуть, что это все чисто предположения, но, по крайней мере, я могу спать сегодня вечером, имея хорошее представление о том, почему это происходит! Я тоже хотел бы услышать мысли других.

Другие вопросы по теме