Вы когда-нибудь пробовали связать три основных API React Native (Animated API, ScrollView, PanResponder API) для создания некоторых шаблонов UI / UX? Если да, то наверняка столкнулись со многими проблемами, которые вызывает эта комбинация. Я решил затронуть эту тему на семинаре, который я провел во время нашего HackerHouse на Бали, и теперь делюсь им с вами.

В видеоуроке и в этом посте я буду обсуждать полезный паттерн в React Native с двумя видами прокрутки. Один - горизонтальный, а другой - вертикальный. Чтобы добиться этого, можно было подумать, что нам нужно всего лишь наложить два вида прокрутки друг на друга. Однако будут подводные камни, с которыми мы столкнемся, и именно здесь на помощь придут Animated и PanResponder. По окончании обучения вы должны лучше понимать API PanResponder, ScrollView и Animated.

Дополнительные семинары см .: Создание и развертывание облачных функций Firebase и правил Firestore - видеоурок

Создание горизонтальных и вертикальных компонентов ScrollView

Horizontal и Vertical ScrollViews есть почти в каждом приложении для Android и iOS. Его можно использовать для отображения нескольких элементов, которые можно прокручивать в обоих направлениях слева направо и справа налево.

В этом руководстве у нас есть вертикальный ScrollView и горизонтальный ScrollView вверху. Вместе они выглядят как на картинке ниже. Вы сможете прокручивать горизонтальный вид влево или вправо и вертикальный вверх или вниз. Одна из важных вещей, которая усложняет эту историю, - это вертикальная прокрутка вверх, вверх, над горизонтальной прокруткой и за верхний край экрана. Если бы они не пересекались, это бы упростило историю.

Вертикальные и горизонтальные компоненты ScrollView

Для начала вам понадобится свежий проект React Native, аналогичный проект, который вы можете получить с React Native Init, добавив компоненты для вертикального и горизонтального просмотра. Исходный код этих компонентов приведен ниже, где вы увидите, что это очень простые компоненты, состоящие из View, ScrollView и Images.

Исходный код Vertical.js / Исходный код Horizontal.js

Компонент Horizontal ScrollView

Для этого компонента он будет иметь ширину, равную ширине экрана, и произвольную высоту 200 пикселей. Эти же размеры будут применены к его дочерним компонентам View и Image. Я также установил для свойства с разбивкой на страницы значение true, чтобы он выглядел мгновенно!

Компонент Vertical ScrollView

Vertical ScrollView настолько прост, насколько вы думаете. Но когда мы объединим их вместе для достижения упомянутой ранее истории, мы столкнемся с некоторыми проблемами.

Проблема: если вы примените абсолютное позиционирование к вертикальному ScrollView, оно больше не будет работать правильно.

Решение. Вот почему мы применили абсолютное позиционирование к горизонтальному ScrollView.

Применяя абсолютное позиционирование к вертикальному ScrollView, мы достигли только одной из наших целей - вертикального просмотра, прокручивающегося поверх экрана. Это больше не выглядело хорошо, поэтому нам пришлось создать компонент, который предотвращает первоначальную блокировку горизонтального ScrollView вертикальным ScrollView. Итак, я создал прозрачный компонент View с той же высотой, что и Horizontal ScrollView или его дочерние элементы, которая составляет 200 пикселей.

Проблема: поскольку вертикальный ScrollView охватывает всю ширину и высоту экрана, вы больше не можете использовать жесты смахивания для горизонтального ScrollView.

Решение: с помощью PanResponder API

PanResponder API - Добавление метода handleSwipe

Как уже упоминалось, мы можем использовать PanResponder API для определения момента касания экрана и выполнения жеста смахивания. Для нашего проекта я определил метод handleSwipe, чтобы установить смещение по оси x нашего компонента Horizontal ScrollView.

handlePanResponderMove - метод

В основном API PanResponder мы определили onStartShouldSetPanResponder как истинное значение. Возможно, для какой-то другой истории вам нужно будет определить условие, чтобы она возвращала истину, но для нашего варианта использования мы можем просто всегда возвращать истину, поскольку мы хотим регистрировать все прикосновения пользователей.

Свойство onPanResponderMove объекта, которое метод PanResponder.create принимает в качестве аргумента, получает функцию, которая принимает два аргумента. Я назвал первый аргумент знаком подчеркивания, чтобы указать, что он не будет использоваться, а второй - gestureState.

Главное свойство, которое нам нужно от gestureState, - это vx, который представляет собой горизонтальную скорость смахивания. Я экспериментировал с этим, регистрируя его, и пороговое значение, которое я решил быть правильным, составляет около 0,7.

Учебник просто фокусируется на сути истории, поэтому мы определили только метод смахивания вправо.

Отладка пользовательского интерфейса

В видео я показал, как прикрепил несколько методов console.log для отображения того, как наш SwipeRight регистрирует касания. Я показал, как, например, если мы смахиваем слишком медленно, будет отображаться false, потому что он не регистрирует этот жест как смахивание. Вот почему ему нужно достичь определенного импульса, чтобы преодолеть порог и зарегистрировать его как смахивание.

Проблема: handlePanResponderMove не имеет естественного способа остановить регистрацию свайпов. Если пользователь проводит пальцем долго или достаточно сильно, он зарегистрирует несколько смахиваний и испортит состояние.

Решение. Сохраните activeIndex как свойство onPanResponderGrant для отслеживания.

Мы устанавливаем activeIndexOnPanResponderGrant равным текущему индексу, который мы сохранили в состоянии. И мы создаем блокировщик для handlePanResponderMove, так что если сохраненный индекс не равен индексу состояния, это означает, что Horizontal ScrollView уже перемещен.

Доработка компонента

Поскольку мы добавили невидимый оверлей, который абсолютно позиционирован, пользователь не может прокручивать вверх и вниз по горизонтальной области. Чтобы решить эту проблему, мы собираемся использовать основной Animated API для привязки смещения широкой прокрутки нашего вертикального ScrollView, уменьшая размер горизонтального наложения после прокрутки вверх.

С помощью Animated API мы включили свойство scaleAnimatedValue нашего компонента приложения. Его значение равно 1, потому что мы хотим, чтобы оверлей сначала начинался со 100% размера. Мы определяем значение scaleTransform равным 1, если вертикальный ScrollView находится вверху, и по мере его прокрутки вниз он будет медленно уменьшаться до 0.

Чтобы увидеть, как мы связываем ScrollView с анимированным компонентом и используемым свойством extrapolate:"clamp", посмотрите наше обучающее видео ниже.

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

В этом руководстве мы показали, как можно использовать три основных API React Native вместе для создания стандартного шаблона UI / UX. Вы всегда можете сравнить свой код с этим полноценным проектом. Пожалуйста, задавайте любые вопросы, которые могут у вас возникнуть, в разделе комментариев, и я отвечу как можно скорее.