Відмова від відповідальності: наступне - це насамперед результат мого власного експерименту в 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% впевнений, що це завжди буде правильно, якщо ви одночасно змінюєте розмір кадру та вмісту подання прокрутки. Але це найкраще, що я можу придумати, і поки ця функція не буде додана в самі рамки , я думаю, що це найкраще, що кожен може зробити.