Відмова від відповідальності: наступне - це насамперед результат мого власного експерименту в React Native 0.50. Наразі в ScrollViewдокументації відсутня багато інформації, яка висвітлюється нижче; наприклад onScrollEndDrag, повністю недокументований. Оскільки тут все покладається на незадокументовану поведінку, я, на жаль, не обіцяю, що ця інформація залишатиметься правильною через рік чи навіть місяць.
Крім того , всі , що нижче передбачає чисто вертикальний Scrollview якого у компенсовано нас цікавить; перекладаємо на x компенсації, якщо потрібно, сподіваємось, легка вправа для читача.
Різні обробники подій під час ScrollViewприйому eventта дозволяють отримати поточну позицію прокрутки через event.nativeEvent.contentOffset.y. Деякі з цих обробників мають дещо іншу поведінку між Android та iOS, як детально описано нижче.
На Android
Створює кожен кадр, коли користувач прокручує, на кожному кадрі, коли подання прокрутки ковзає після того, як користувач відпустить його, на остаточному кадрі, коли огляд прокрутки перебуває в спокої, а також коли зміщення погляду прокрутки змінюється в результаті його кадру змінюється (наприклад, через обертання від пейзажу до портрета).
На iOS
Створюється під час перетягування користувачем або під час перегляду прокрутки, з деякою частотою, що визначається scrollEventThrottleі, максимум, один раз на кадр, коли scrollEventThrottle={16}. Якщо користувач випустить подання прокрутки, поки у нього є достатній імпульс для ковзання, onScrollобробник також вистрілить, коли стане спокою після плавання. Однак, якщо користувач перетягує , а потім відпускає вид прокрутки , поки вона знаходиться в нерухомому стані , onScrollце НЕ гарантує вогню для кінцевої позиції , якщо scrollEventThrottleне було встановлено таким чином, щоonScroll пожежі кожен кадр прокрутки.
Існує вартість продуктивності налаштування, scrollEventThrottle={16}яку можна зменшити, встановивши її на більшу кількість. Однак це означає, що onScrollне запустить кожен кадр.
Запускається, коли вигляд прокрутки припиняється після ковзання. Зовсім не спрацьовує, якщо користувач випускає подання прокрутки, поки він нерухомий, щоб він не ковзав.
onScrollEndDrag
Створюється, коли користувач перестає перетягувати подання прокрутки - незалежно від того, чи подання прокрутки залишається нерухомим або починає ковзати.
Враховуючи ці відмінності в поведінці, найкращий спосіб відстежувати компенсацію залежить від ваших точних обставин. У найскладнішому випадку (вам потрібно підтримувати Android та iOS, включаючи обробку змін у ScrollViewкадрі з-за обертання, і ви не хочете приймати покарання продуктивності на Android від налаштування scrollEventThrottleдо 16), і вам потрібно впоратися змінюється і вміст у вікні прокрутки, то це правильний чорт.
Найпростіший випадок - якщо вам потрібно лише обробляти Android; просто використовуйте onScroll:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
>
Для додаткової підтримки iOS, якщо ви раді запустити onScrollобробник кожного кадру та прийняти наслідки для продуктивності, а якщо вам не потрібно обробляти зміни кадру, то це лише трохи складніше:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={16}
>
Щоб зменшити накладні показники продуктивності на iOS, при цьому гарантуючи, що ми записуємо будь-яку позицію, на якій переглядається прокрутка, ми можемо збільшити scrollEventThrottleта додатково надати onScrollEndDragобробник:
<ScrollView
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y
}}
scrollEventThrottle={160}
>
Але якщо ми хочемо обробляти зміни кадру (наприклад, тому що ми дозволяємо повертати пристрій, змінюючи доступну висоту для кадру перегляду прокрутки) та / або змінюючи вміст, тоді ми повинні додатково реалізувати обидва onContentSizeChangeта onLayoutслідкувати за висотою обох кадр подання прокрутки та його вміст і, таким чином, постійно обчислюють максимально можливе зміщення та підсумок, коли зміщення було автоматично зменшено за рахунок зміни розміру кадру чи вмісту:
<ScrollView
onLayout={event => {
this.frameHeight = event.nativeEvent.layout.height;
const maxOffset = this.contentHeight - this.frameHeight;
if (maxOffset < this.yOffset) {
this.yOffset = maxOffset;
}
}}
onContentSizeChange={(contentWidth, contentHeight) => {
this.contentHeight = contentHeight;
const maxOffset = this.contentHeight - this.frameHeight;
if (maxOffset < this.yOffset) {
this.yOffset = maxOffset;
}
}}
onScroll={event => {
this.yOffset = event.nativeEvent.contentOffset.y;
}}
onScrollEndDrag={event => {
this.yOffset = event.nativeEvent.contentOffset.y;
}}
scrollEventThrottle={160}
>
Так, це жахливо. Я також не на 100% впевнений, що це завжди буде правильно, якщо ви одночасно змінюєте розмір кадру та вмісту подання прокрутки. Але це найкраще, що я можу придумати, і поки ця функція не буде додана в самі рамки , я думаю, що це найкраще, що кожен може зробити.