Анимация градиентов в React Native

Я работаю над личным проектом под названием KaoCards, приложение-флэш-карта для запоминания имен и лиц людей. Когда я проектировал продукт, я думал, что было бы здорово иметь анимированный градиент в качестве фона, но когда я попытался реализовать его, оказалось, что это было больше работы, чем я думал.

Итак, вот история о том, как мне удалось заставить его работать. Если вы хотите TL; DR, я сделал хранилище, за которым вы можете следить.

Наивная попытка.

Если вы хотите понять это, важно знать, почему моя первая попытка не сработала.

Чтобы отобразить градиент в React Native, люди используют проект под названием реагировать-нативный-линейный градиент. Я хотел посмотреть, пытался ли кто-нибудь анимировать цвета, и я нашел пример «Анимированный переход градиента» в этом репо. Просматривая код, у меня была такая реакция:

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

  1. Создайте компонент AnimatedLinearGradient, используя Animate.createAnimatedComponent
  2. Интерполируйте некоторые цвета и передавайте их в AnimatedLinearGradient

Просто, правда? Вот источник (он потерпит крах). Я сделал экспериментальное приложение, запустил его, а затем womp womp. Мы получаем ошибку:

Значение JSON `` типа NSNull нельзя преобразовать в UIColor. Вы забыли вызвать processColor () на стороне JS?

Что-то где-то внизу линии не получало значений цветов. Поэтому я обратился к Твиттеру за помощью:

Джейсон Браун ответил с ключевой проницательностью:

Аааааа хорошо Анимированные не работают с массивами. Хотя я думал, что все делаю правильно, библиотека Animated не обрабатывает значения свойств массива, поэтому основной нативный компонент получает мусор вместо получения анимированных цветов.

Стало понятно, почему оригинальный пример был таким большим.

Строить это правильно.

Хорошо, понимая это ограничение для Animated, давайте изменим наш игровой план и сделаем его немного более надежным.

  1. Мы хотим, чтобы наш основной компонент, AnimatedGradient, работал так же, как LinearGradient. Это должно занять множество цветов.
  2. Мы хотим, чтобы переход произошел, когда мы изменили цветовую опору. Для этого AnimatedGradient необходимо отслеживать предыдущие цвета.
  3. Поскольку мы не можем анимировать значения в массивах, мы можем создать компонент GradientHelper, который принимает цвета по отдельности, и вызвать для этого Animated.createAnimatedComponent. GradientHelper поместит значения в массив и передаст их компоненту LinearGradient из пакета Reaction-native-linear-Gradient.

Для простоты в этом примере мы будем предполагать, что массив цветов имеет только 2 значения.

Компонент AnimatedGradient

Исходный код

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

В конструкторе AnimatedGradient мы инициализируем поле состояния prevColors для отслеживания предыдущих цветов. Мы также инициализируем Animated.Value с именем tweener.

В getDerivedStateFromProps мы берем значение state.colors и вставляем в state.prevColors. Мы устанавливаем новый state.colors и сбрасываем твинер.

В componentWillUpdate (иначе, когда меняется реквизит), мы заставим анимацию движения перемещаться от 0 до 1.

В методе рендеринга мы используем анимацию движения, prevColors и цвета, чтобы создать две цветовые интерполяции и передать их по отдельности нашему AnimatedGradientHelper.

Градиент помощник

Исходный код

В GradientHelper все, что мы делаем, это берём реквизиты color1 и color2, помещаем их в массив и передаем в LinearGradient. Мы делаем это, потому что нам нужно обойти ограничения Animated.

И это суть этого. Вот демо:

Теперь мы знаем, почему оригинальный пример такой большой. Он должен был делать все это и обрабатывать градиенты с более чем 2 цветами.

Но подождите, что еще мы можем оживить?

Мы действительно можем пойти на дополнительный шаг и анимировать другие свойства. Компонент LinearGradient позволяет указывать координаты начала и конца градиента. Почему бы не интерполировать их тоже? Вот обновленный метод рендеринга. Вы, вероятно, можете догадаться, что произошло в остальной части компонента. Источник

Нам просто нужно немного настроить наш GradientHelper, сделав что-нибудь с реквизитом. Источник

И теперь у нас есть кулер демо.

Мне удалось объединить этот анимированный градиент с некоторыми другими анимациями, чтобы создать крутой фоновый эффект для моего проекта KaoCards:

Итак, теперь вы знаете, как анимировать градиенты в React Native, и немного больше о том, как работает Animated. Какие еще свойства вы можете оживить?

Спасибо Джейсону Брауну за предоставленную информацию. Все, что я узнал об анимации в React Native, я узнал от него. Обязательно следите за ним в Твиттере и ознакомьтесь с его курсом React Native Animations.