Статьи

Анимируйте свое приложение React Native

Анимация является важной частью дизайна пользовательского опыта. Он служит в качестве обратной связи о пользовательских действиях, информирует пользователей о состоянии системы и помогает им взаимодействовать с интерфейсом.

React Native — это один из инструментов, который я использую для создания кроссплатформенных мобильных приложений, поэтому в этом руководстве я расскажу, как реализовать анимацию на этой платформе. Окончательным результатом этого урока будет приложение для кухонной раковины, которое реализует различные виды анимации. Вот как это будет выглядеть:

React Native Animations Приложение для кухонной раковины

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

  • реагировать
    Как создать программу чтения новостей с помощью React Native: компонент «Настройка» и «Элемент новостей»
  • реагировать
    Как создать программу чтения новостей с React Native: компонент веб-страницы
  • React Native
    Как создать приложение для обнаружения лиц с помощью React Native

Мы будем специально работать на платформе Android, но код, используемый в этом руководстве, должен работать и на iOS. На самом деле, если вы не хотите испытывать трудности при настройке нового проекта React Native, я рекомендую вам попробовать React Native Web Starter . Это позволяет вам создать новый проект React Native, который вы можете просмотреть в браузере. Это дает преимущество в том, что вам не нужно настраивать устройство и ускоряет горячую перезагрузку, чтобы вы могли быстрее просматривать изменения.

Если вы еще этого не сделали, создайте новый проект React Native:

1
react-native init RNAnimation

Если вы используете React Native Web Starter, вот как вы создаете новый проект:

1
2
3
4
git clone https://github.com/grabcode/react-native-web-starter.git RNAnimation
cd RNAnimation
rm -rf .git
npm install

Откройте файл index.android.js (или index.web.js ), удалите код по умолчанию и добавьте следующее:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
import React, { Component } from ‘react’;
import { App } from ‘./app/components/App’;
 
import {
  AppRegistry,
  View
} from ‘react-native’;
 
class RNAnimation extends Component {
  render() {
    return (
      <View>
        <App />
      </View>
    );
  }
}
 
AppRegistry.registerComponent(‘RNAnimation’, () => RNAnimation);

Если вы используете React Native для Web, вы можете пропустить этот шаг, поскольку код по умолчанию уже настроен для использования компонента App .

Создайте папку app/components и внутри создайте файл App.js Это будет основной файл, с которым мы будем работать. Создав файл, вы можете продолжить и импортировать пакеты, которые вам понадобятся для всего проекта.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
import React, { Component } from ‘react’;
 
import {
  Platform,
  StyleSheet,
  Text,
  ScrollView,
  View,
  Image,
  TouchableHighlight,
  Switch,
  Dimensions,
  Animated,
  Easing,
  LayoutAnimation,
  UIManager
} from ‘react-native’;

Если вы ранее занимались разработкой React Native, вы уже должны быть хорошо знакомы со следующими компонентами. Если нет, взгляните на документы React Native API .

1
2
3
4
5
6
7
8
9
Platform,
StyleSheet,
Text,
ScrollView,
View,
Image,
TouchableHighlight,
Switch,
Dimensions,

Это пакеты, которые специально используются для реализации анимации:

1
2
3
4
Animated,
Easing,
LayoutAnimation,
UIManager

Вот краткий обзор каждого из них:

  • Анимированные : позволяет создавать анимированные компоненты. React Native имеет четкое разделение между анимированными и статическими компонентами. В частности, вы можете создавать анимированные представления ( <Animated.View> ), текст ( <Animated.Text> ) и изображения ( <Animated.Image> ).
  • Облегчение : общий контейнер постоянных значений для облегчения анимации.
  • LayoutAnimation : для выполнения различных видов анимаций при изменении макета (например, при обновлении состояния).
  • UIManager : в настоящее время LayoutAnimation все еще является экспериментальной функцией на Android. Импорт UIManager позволяет нам включить его. Для iOS LayoutAnimation работает по умолчанию, поэтому вам не нужно импортировать UIManager .

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

В React Native вы можете создать новое анимированное значение, вызвав метод Value() в классе Animated . Затем укажите начальное анимированное значение в качестве аргумента.

1
2
3
4
constructor(props){
    super(props);
    this.spinValue = new Animated.Value(0);
}

Затем создайте функцию, которая будет выполнять анимацию поворота.

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

Затем мы создаем новую временную анимацию, вызывая функцию Animated.timing() . Это принимает текущее анимированное значение в качестве первого аргумента и объект, содержащий конфигурацию анимации, в качестве второго. Объект должен содержать конечное значение для анимированного значения, продолжительность (в миллисекундах) и тип замедления анимации.

Наконец, вызовите метод start() чтобы запустить анимацию.

01
02
03
04
05
06
07
08
09
10
11
spin() {
  this.spinValue.setValue(0);
  Animated.timing(
    this.spinValue,
    {
      toValue: 1,
      duration: 1500,
      easing: Easing.linear
    }
  ).start();
}

Последний шаг — реализовать анимацию. Внутри вашего метода render() определите, как будет изменяться значение поворота. Это можно сделать, вызвав функцию interpolate() . Он принимает объект, содержащий inputRange и outputRange . inputRange — это массив, содержащий начальное и конечное значение вращения. outputRange — это массив, содержащий фактические значения вращения.

Поэтому изначально анимируемый объект будет вращаться на 0 градусов, а окончательное значение будет 360 градусов. Это вращение выполняется в течение 1500 миллисекунд, как определено ранее в конфигурации анимации.

1
2
3
4
const spin = this.spinValue.interpolate({
  inputRange: [0, 1],
  outputRange: [‘0deg’, ‘360deg’]
});

При рендеринге компонента значение поворота добавляется в качестве преобразования в стили. Так что, если вы знакомы с CSS-анимацией, это эквивалентная реализация в React Native.

01
02
03
04
05
06
07
08
09
10
11
12
13
return (
    <Animated.Image
      style={[
        styles.spinner,
        {
          transform: [
            {rotate: spin}
          ]
        }
      ]}
      source={{uri: ‘../../img/loading.png’}}
    />
);

Теперь, когда вы знаете основы создания анимации, давайте создадим еще несколько, чтобы вы знали, как реализовывать различные виды. Внутри вашего constructor() создайте объект, содержащий анимации, которые мы реализуем:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
var animations = [
  {
    animation: ‘spin’,
    enabled: false
  },
  {
    animation: ‘scale’,
    enabled: false
  },
  {
    animation: ‘opacity’,
    enabled: false
  },
  {
    animation: ‘colorChange’,
    enabled: false
  },
  {
    animation: ‘parallelTranslateX’,
    enabled: false
  }
];

Не волнуйтесь, если вы не знаете, что каждый из них делает — я собираюсь рассказать вам обо всех. Все, что вам нужно знать на данный момент, это то, что эта конфигурация указывает, включена ли анимация в настоящее время или нет. После инициализации добавьте массив animations в состояние:

1
2
3
this.state = {
    animations: animations
};

В вашей функции render() добавьте компоненты, которые мы будем анимировать, а также список анимаций.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
return (
  <View style={styles.container}>
       
    <Animated.Image
      style={[
        styles.spinner,
        {
          transform: [
            {rotate: spin}
          ]
        }
      ]}
      source={{uri: ‘../../img/loading.png’}}
    />
 
    <Animated.View />
         
    <ScrollView>
    {this.renderAnimationsList()}
    </ScrollView>
 
    <Animated.View />
 
    <Animated.View />
  </View>
);

Функция renderAnimationsList() отображает список анимаций с использованием компонентов Switch и Text .

01
02
03
04
05
06
07
08
09
10
11
12
13
renderAnimationsList() {
  return this.state.animations.map((item) => {
    return (
      <View style={styles.item} key={item.animation}>
        <Switch
          onValueChange={(value) => this.toggleAnimation(item.animation, value)}
          style={styles.switch}
          value={item.enabled} />
        <Text style={styles.animation_type}>{item.animation}</Text>
      </View>
    );
  });
}

Switch позволяет пользователю включать и выключать анимацию. Каждый раз, когда пользователь toggleAnimation() переключатель, toggleAnimation() функция toggleAnimation() . Все, что он делает, — это находит соответствующую анимацию и обновляет значение enabled свойства до выбранного значения. Затем он обновляет состояние с обновленными значениями и просматривает все анимации, выполняя только включенные.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
toggleAnimation(animation, value) {
  var animations = this.state.animations;
  var index = animations.findIndex((obj) => {
    return obj.animation == animation;
  });
 
  animations[index].enabled = value;
 
  this.setState({
    animations: animations
  });
 
  animations.forEach((item) => {
    if(item.enabled){
      this[item.animation]();
    }
  });
}

Также добавьте стили, которые будут использоваться в приложении.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
const styles = StyleSheet.create({
 container: {
    flex: 1,
    alignItems: ‘center’,
    flexDirection: ‘column’
  },
  button: {
    height: 40,
    backgroundColor: ‘#eee’,
    justifyContent: ‘center’,
    alignItems: ‘center’,
    marginTop: 10
  },
  item: {
    flex: 2,
    flexDirection: ‘row’,
    height: 50,
  },
  switch: {
    marginBottom: 10
  },
  animation_type: {
    marginLeft: 10
  },
  spinner: {
    marginTop: 20,
    alignSelf: ‘center’,
    width: 50,
    height: 50
  },
  box: {
    width: 50,
    height: 50,
    zIndex: 100
  },
  red_box: {
    backgroundColor: ‘red’,
    marginBottom: 20
  },
  blue_box: {
    alignSelf: ‘flex-start’,
    backgroundColor: ‘blue’
  },
  green_box: {
    alignSelf: ‘flex-end’,
    backgroundColor: ‘green’
  },
  squares_container: {
    flexDirection: ‘row’,
    flex: 1,
    flexWrap: ‘wrap’
  },
  square: {
    width: 35,
    height: 35,
    backgroundColor: ‘lightblue’,
    margin: 10
  },
  number: {
    fontSize: 20,
    fontWeight: ‘bold’
  }
});

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

1
this.scaleValue = new Animated.Value(0);

Создайте функцию для анимации масштаба. Это похоже на функцию spin() ; единственная разница — это функция замедления, которую мы используем. Здесь мы используем easeOutBack чтобы сделать масштабирование более easeOutBack . Это полезно, особенно если эта анимация выполняется повторно. Если вы хотите узнать, какие другие функции замедления вы можете использовать, обратитесь к easings.net . Все перечисленные здесь варианты можно использовать в React Native.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
scale () {
  this.scaleValue.setValue(0);
  Animated.timing(
    this.scaleValue,
    {
      toValue: 1,
      duration: 1500,
      easing: Easing.easeOutBack
    }
  ).start(() => {
    if(this.state.animations[0].enabled){
      this.scale();
    }
  });
}

Другое новшество в функции выше — это то, что мы передаем функцию в качестве аргумента функции start() . Эта функция выполняется после завершения анимации. Здесь мы проверяем, включена ли анимация, и если она есть, мы снова вызываем ту же функцию. Это позволяет нам выполнять анимацию повторно, пока она включена.

1
2
3
4
5
() => {
    if(this.state.animations[0].enabled){
      this.scale();
    }
}

Затем в функции render() настройте интерполяцию масштабирования. На этот раз у нас есть три значения для входного и выходного диапазона, чтобы создать пульсирующий эффект, такой как сердцебиение. Это позволяет нам создавать масштабную анимацию, которая не делает объект внезапно больше или меньше. Максимальный выходной диапазон равен 7, поэтому объект будет в семь раз больше своего первоначального размера.

1
2
3
4
const nearFar = this.scaleValue.interpolate({
  inputRange: [0, 0.5, 1],
  outputRange: [1, 7, 1]
});

Чтобы сэкономить место, просто добавьте scale преобразование к тому же компоненту, который мы использовали ранее:

01
02
03
04
05
06
07
08
09
10
11
12
<Animated.Image
  style={[
    styles.spinner,
    {
      transform: [
        {rotate: spin},
        {scale: nearFar}
      ]
    }
  ]}
  source={{uri: ‘../../img/loading.png’}}
/>

Добавив эти два преобразования, вы теперь можете включить анимацию вращения и масштаба для их одновременного выполнения.

К настоящему времени вы должны были заметить шаблоны, которые позволяют нам создавать анимацию. Много кода повторяется при выполнении анимации. Лучшей практикой будет создание функций, инкапсулирующих повторяющийся код, но для простоты и легкости понимания давайте придерживаться необработанного кода для остальной анимации.

Теперь давайте попробуем анимировать прозрачность компонента. К настоящему времени вы должны быть хорошо знакомы с тем, куда идет каждый фрагмент кода, поэтому я больше не буду упоминать, где вы разместите каждый из них. Но если вы запутались, вы можете просто посмотреть на код на GitHub :

1
this.opacityValue = new Animated.Value(0);

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
opacity() {
  this.opacityValue.setValue(0);
  Animated.timing(
    this.opacityValue,
    {
      toValue: 1,
      duration: 3000,
      easing: Easing.linear
    }
  ).start(() => {
    if(this.state.animations[2].enabled){
      this.opacity();
    }
  });
}

Измените непрозрачность с видимого на прозрачный, а затем снова видимый в течение трех секунд.

1
2
3
4
const opacity = this.opacityValue.interpolate({
  inputRange: [0, 0.5, 1],
  outputRange: [1, 0, 1]
});

Создайте новый компонент, прозрачность которого будет контролироваться:

1
2
3
4
<Animated.View style={[
  styles.box, {opacity}
  ]}
/>

Далее давайте попробуем анимировать цвет фона компонента:

1
this.colorValue = new Animated.Value(0);

На этот раз мы анимируем в течение пяти секунд:

01
02
03
04
05
06
07
08
09
10
11
colorChange() {
  this.colorValue.setValue(0);
  Animated.timing(this.colorValue, {
    toValue: 100,
    duration: 5000
  }).start(() => {
    if(this.state.animations[3].enabled){
        this.colorChange();
    }
  });
}

У нас есть три цвета для работы. Первоначальный цвет — желтый, а затем через несколько секунд он полностью изменится на оранжевый, а затем на красный. Обратите внимание, что цвета не будут резко меняться; все цвета между указанными вами цветами также будут показаны. React Native автоматически вычисляет значения цвета между указанными вами. Вы можете увеличить длительность, если хотите увидеть, как цвет меняется со временем.

1
2
3
4
const colorAnimation = this.colorValue.interpolate({
  inputRange: [0, 50, 100],
  outputRange: [‘yellow’, ‘orange’, ‘red’]
});

Как и непрозрачность, интерполированное значение добавляется как стиль:

1
2
3
4
5
<Animated.View style={[
  styles.box, {opacity},
  {backgroundColor: colorAnimation},
  ]}
/>

Вы можете сказать, что мы уже выполняли анимацию параллельно. Но это всего лишь побочный эффект от разных преобразований, прикрепленных к одному компоненту. Если вы хотите выполнить несколько анимаций одновременно, вам нужно использовать функцию parallel() из Animated API. Это принимает массив функций анимации для выполнения. В приведенном ниже примере у нас есть два анимированных значения, по одному для каждого компонента, который мы хотим анимировать.

1
2
this.blue_box_X = new Animated.Value(0);
this.green_box_X = new Animated.Value(0);

В функции анимации мы устанавливаем начальные анимированные значения как обычно. Но под ним мы используем Animated.parallel() чтобы сгруппировать все анимации, которые мы хотим выполнить. В этом случае у нас есть только две временные анимации, которые выполняются в течение двух секунд. Также обратите внимание, что мы не вызываем метод start() для каждой анимации. Вместо этого мы используем его после объявления параллельной анимации. Это позволяет нам запускать анимацию одновременно.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
parallelTranslateX() {
  this.blue_box_X.setValue(0);
  this.green_box_X.setValue(0);
  Animated.parallel([
      Animated.timing(
        this.blue_box_X,
        {
          toValue: 1,
          duration: 2000,
          easing: Easing.linear
        }
      ),
      Animated.timing(
        this.green_box_X,
        {
          toValue: 1,
          duration: 2000,
          easing: Easing.linear
        }
      )
  ]).start(() => {
    if(this.state.animations[4].enabled){
      this.parallelTranslateX();
    }
  });
}

Чтобы интерполяция имела смысл, сначала проверьте стиль, который мы добавили для двух полей ранее:

1
2
3
4
5
6
7
8
blue_box: {
  alignSelf: ‘flex-start’,
  backgroundColor: ‘blue’
},
green_box: {
  alignSelf: ‘flex-end’,
  backgroundColor: ‘green’
},

Синяя рамка выровнена с помощью flex-start , что означает, что она выровнена влево. Зеленый прямоугольник имеет flex-end , который выровнен по правому краю. (По крайней мере, так они работают, если контейнер имеет flexDirection . В противном случае это другая история.)

Обладая этим знанием, мы можем теперь перемещать коробки куда угодно. Но для этого урока все, что мы хотим сделать, это переместить блоки в противоположность их начальным позициям. Таким образом, синее поле перемещается вправо, а зеленое поле перемещается влево. Именно здесь поступают данные измерений устройства. Мы используем width устройства для вычисления окончательного значения интерполяции, чтобы поле не выходило за пределы.

1
var {width} = Dimensions.get(‘window’);

В этом случае мы просто вычитаем 50 из ширины устройства, чтобы синий прямоугольник направился вправо. А для зеленой рамки мы конвертируем ширину устройства в ее отрицательный эквивалент, чтобы оно двигалось влево. Вам может быть интересно, почему 50? Это потому, что размер каждой коробки составляет 50 . Коробка все равно выйдет за пределы, если мы не вычтем ее собственный размер из ширины устройства.

1
2
3
4
5
6
7
8
9
const blue_box_translateX = this.blue_box_X.interpolate({
  inputRange: [0, 1],
  outputRange: [0, width — 50],
});
 
const green_box_translateX = this.green_box_X.interpolate({
  inputRange: [0, 1],
  outputRange: [0, -width + 50],
});

Наконец, добавьте компоненты для анимации. Рассматриваемое преобразование — translateX , которое позволяет нам изменять положение объекта на оси X, чтобы перемещать его горизонтально.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<Animated.View style={[
  styles.box,
  styles.blue_box,
  {
    transform: [
      {
        translateX: blue_box_translateX
      }
    ]
  }
  ]}
/>
 
<Animated.View style={[
  styles.box,
  styles.green_box,
  {
    transform: [
      {
        translateX: green_box_translateX
      }
    ]
  }
  ]}
/>

Помимо параллельных анимаций, есть также последовательности и пошаговые анимации.

Их реализация аналогична параллельной анимации в том смысле, что все они принимают массив анимаций для выполнения. Но определяющим фактором для последовательных анимаций является то, что анимации, которые вы указали в массиве, будут выполняться последовательно. Вы также можете добавить дополнительные задержки для каждой анимации, если хотите.

С другой стороны, пошаговая анимация представляет собой комбинацию параллельной и последовательной анимации. Это потому, что он позволяет запускать анимации как параллельно, так и последовательно. Вот ручка, которая демонстрирует потрясающую анимацию .

Другим инструментом, который React Native предоставляет для реализации анимации, является LayoutAnimation . Это позволяет вам анимировать виды на их новые позиции, когда происходит следующий макет. Изменения макета обычно происходят при обновлении состояния. Это приводит к тому, что определенный компонент пользовательского интерфейса либо добавляется, обновляется, либо удаляется с экрана.

Когда эти события происходят, LayoutAnimation заботится об анимации соответствующего компонента. Например, в приложении списка дел, когда вы добавляете новый элемент списка дел, оно автоматически добавляет анимацию весны, чтобы создать новый элемент.

Давайте добавим LayoutAnimation в приложение для кухонной раковины. Как упоминалось ранее, вам необходимо импортировать LayoutAnimation , Platform и UIManager в приложение. Затем в своем constructor() добавьте код для включения LayoutAnimation на Android:

1
2
3
if (Platform.OS === ‘android’){
  UIManager.setLayoutAnimationEnabledExperimental(true);
}

(В iOS LayoutAnimation должна работать по умолчанию. Если вы используете React Native для Web, LayoutAnimation не поддерживается , поэтому вам нужно будет экспортировать приложение на Android или iOS и попробовать его оттуда.)

Затем, прямо под ScrollView который содержит список анимаций, добавьте кнопку для создания квадратов, которые будут отображаться на экране:

1
2
3
4
5
<View>
  <TouchableHighlight style={[styles.button]} onPress={this.addSquares.bind(this)}>
    <Text>Add Squares</Text>
  </TouchableHighlight>
</View>

По сути, это будет генерировать три маленьких квадрата каждый раз, когда пользователь нажимает кнопку « Добавить квадраты» .

Вот функция для добавления квадратов:

1
2
3
4
5
6
7
addSquares() {
  LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
  var squares = this.state.squares;
  this.setState({
    squares: squares + 3
  });
}

Идея состоит в том, чтобы вызвать LayoutAnimation.configureNext() перед обновлением состояния. Это принимает анимацию, которую вы хотите использовать. В стандартной комплектации LayoutAnimation поставляется с тремя предустановками: linear , spring и easeInEaseOut . Это должно работать в большинстве случаев, но если вам нужно настроить анимацию, вы можете прочитать документацию по LayoutAnimation, чтобы узнать, как создать свою собственную.

Внутри функции render() создайте цикл for который будет визуализировать квадраты. Количество генерируемых квадратов зависит от текущего значения squares в состоянии.

1
2
3
4
var squares = [];
for(var i = 0; i < this.state.squares; i++){
  squares.push(this.renderSquare(i));
}

Функция renderSquare() — это та, которая фактически рендерит квадраты:

1
2
3
4
5
renderSquare(key) {
  return (
    <Animated.View key={key} style={styles.square} />
  );
}

Анимированный API-интерфейс React Native очень надежен и настраиваем, но, как вы уже видели, это связано с тем недостатком, что приходится писать много кода только для реализации очень простых анимаций. Итак, в этом последнем разделе я познакомлю вас с двумя сторонними библиотеками, которые позволят вам реализовать обычную анимацию с меньшим количеством кода.

Если вы создаете приложение, которое нуждается в анимации чисел (например, приложение секундомера или счетчика), вы можете использовать встроенную функцию setInterval() чтобы обновить состояние через заданный интервал, а затем реализовать анимацию самостоятельно.

Или, если хотите, вы можете использовать библиотеку Animate Number . Это позволяет легко реализовывать анимацию чисел, например настраивать переход при каждом обновлении числа. Вы можете установить его с помощью следующей команды:

1
npm install react-native-animate-number —save

После установки импортируйте его в свое приложение:

1
import AnimateNumber from ‘react-native-animate-number’;

Затем используйте его как компонент:

1
<AnimateNumber style={styles.number} value={100} countBy={1} />

То, что делает приведенный выше код, считается до 100, начиная с 0.

Если вы хотите реализовать анимацию общего назначения, например, предлагаемую библиотекой animate.css , есть эквивалентная библиотека для React Native, которая называется Animatable . Вы можете установить его с помощью следующей команды:

1
npm install react-native-animatable —save

После установки импортируйте его с помощью следующего кода:

1
import * as Animatable from ‘react-native-animatable’;

Вот пример использования кода, который мы добавили ранее для нашей анимации макета. Все, что вам нужно сделать, это использовать <Animatable.View> вместо <Animated.View> а затем добавить ref чтобы мы могли ссылаться на этот компонент с помощью кода JavaScript.

1
2
3
<Animatable.View style={styles.squares_container} ref=»squares»>
{squares}
</Animatable.View>

Затем создайте метод resetSquares() . Это удалит все квадраты, которые в данный момент находятся на экране. Используйте this.refs.squares для обращения к контейнеру квадратов, а затем вызовите zoomOutUp() чтобы анимировать его вне поля зрения, используя анимацию уменьшения масштаба с направлением вверх. И не забудьте обновить состояние после завершения анимации. Это общий шаблон при реализации анимации. Сделайте анимацию перед обновлением состояния.

1
2
3
4
5
6
7
resetSquares() {
  this.refs.squares.zoomOutUp(1500).then(() => {
    this.setState({
      squares: 0
    });
  });
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
addSquares() {
  LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
  var squares = this.state.squares;
   
  if(squares == 0){
    this.setState({
      squares: squares + 3
    }, () => {
      this.refs.squares.zoomInDown(1);
    });
  }else{
    this.setState({
      squares: squares + 3
    });
  }
}

Это оно! В этой статье вы узнали основы создания анимации в React Native. Анимации могут быть реализованы с использованием Animated API, LayoutAnimations и сторонних библиотек.

Как вы уже видели, создание анимации может занять значительное количество кода, даже для простых, таких как масштабируемая анимация. Это дает то преимущество, что вы можете настраивать анимацию так, как вам удобно.

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

  • React Native Animations Использование Animated API : руководство для начинающих по внедрению различных видов анимации в React Native. Этот учебник охватывает анимации последовательности и ошеломления, если вы хотите узнать о них больше.
  • React Native Animation Book : все еще в стадии разработки, но, тем не менее, ценный ресурс. В нем есть почти все, что вы хотите знать об анимациях в React Native, например, если вы хотите анимировать что-либо при пользовательской прокрутке или если вы хотите перетаскивать объекты вокруг.
  • Документы React Native — Анимации : если вы хотите узнать конкретные детали реализации анимации в React Native.
  • Анимация в Mobile UX Design : не совсем относится к React Native, но в целом к ​​анимации мобильных приложений. Это хорошая статья как для UX-дизайнеров, так и для разработчиков, чтобы иметь общее представление о том, как показывать значимые анимации пользователям.

Наконец, если вы хотите узнать больше о CSS-анимации, ознакомьтесь с некоторыми из наших видеокурсов.

  • Анимация
    9 популярных курсов по CSS-анимации
    Эндрю Блэкман