Перейти к содержанию

Анимация элементов между экранами

В этом руководстве рассказывается о том, как анимировать элементы между экранами. Эта возможность известна как Shared Element Transition и реализована в @react-navigation/native-stack с помощью React Native Reanimated.

Примечание

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

Анимация элементов между экранами

Предварительные условия

Прежде чем продолжить работу над этим руководством, убедитесь, что ваше приложение соответствует этим критериям:

Минимальный пример

Чтобы создать общий переход, выполните следующие действия:

  1. Используйте компоненты Animated, импортированные из react-native-reanimated.
  2. Присвойте один и тот же тег sharedTransitionTag элементам на разных экранах.
  3. Перемещайтесь между экранами. Переход начнется автоматически.
 1
 2
 3
 4
 5
 6
 7
 8
 9
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
64
65
66
67
68
69
70
71
72
73
import * as React from 'react';
import { View, Button, StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

import Animated from 'react-native-reanimated';

// highlight-next-line
const Stack = createNativeStackNavigator();

function HomeScreen({ navigation }) {
    return (
        <View style={styles.container}>
            <Button
                title="Go to Details"
                onPress={() =>
                    navigation.navigate('Details')
                }
            />
            <Animated.Image
                source={{
                    uri: 'https://picsum.photos/id/39/200',
                }}
                style={{ width: 300, height: 300 }}
                // highlight-next-line
                sharedTransitionTag="tag"
            />
        </View>
    );
}

function DetailsScreen({ navigation }) {
    return (
        <View style={styles.container}>
            <Button
                title="Go back"
                onPress={() => navigation.goBack()}
            />
            <Animated.Image
                source={{
                    uri: 'https://picsum.photos/id/39/200',
                }}
                style={{ width: 100, height: 100 }}
                // highlight-next-line
                sharedTransitionTag="tag"
            />
        </View>
    );
}

export default function App() {
    return (
        <NavigationContainer>
            <Stack.Navigator>
                <Stack.Screen
                    name="Home"
                    component={HomeScreen}
                />
                <Stack.Screen
                    name="Details"
                    component={DetailsScreen}
                />
            </Stack.Navigator>
        </NavigationContainer>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
    },
});

sharedTransitionTag - это строка, которая должна быть уникальной в контексте одного экрана, но должна соответствовать элементам между экранами. Этот реквизит позволяет Reanimated идентифицировать и анимировать элементы, аналогично свойству key, которое сообщает React, какой элемент в списке является таковым.

Настройка перехода

По умолчанию переход анимирует свойства width, height, originX, originY и transform с помощью withTiming с длительностью 500 мс. Вы можете легко настроить реквизиты width, height, originX и originY. Также возможна настройка transform, но это выходит далеко за рамки данного руководства.

Примечание

API пользовательского перехода SharedTransition не доработан и может измениться в будущем выпуске.

Для настройки перехода необходимо передать все свойства, кроме transform.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { SharedTransition } from 'react-native-reanimated';

const customTransition = SharedTransition.custom(
    (values) => {
        'worklet';
        return {
            height: withSpring(values.targetHeight),
            width: withSpring(values.targetWidth),
            originX: withSpring(values.targetOriginX),
            originY: withSpring(values.targetOriginY),
        };
    }
);

function HomeScreen() {
    return (
        <Animated.Image
            style={{ width: 300, height: 300 }}
            sharedTransitionTag="tag"
            // highlight-next-line
            // add this to both elements on both screens
            sharedTransitionStyle={customTransition}
        />
    );
}

Ссылка

Полную справку по переходам между общими элементами можно найти в документации по React Native Reanimated.

Альтернативы

В качестве альтернативы можно использовать библиотеку react-native-shared-element с привязкой React Navigation, которая реализует переходы между общими элементами в навигаторе @react-navigation/stack на основе JS. Однако это решение активно не поддерживается.

В react-native-navigation также реализована поддержка Shared Element Transitions. Подробнее об этом можно прочитать здесь.

Ссылки

Комментарии