Skip to main content
Version: 7.x

在屏幕之间设置动画元素

本指南介绍了如何在屏幕之间制作元素动画。此功能称为 共享元素转换,并在 @react-navigation/native-stackReact Native 复活 中实现。

¥This guide covers how to animate elements between screens. This feature is known as a Shared Element Transition and it's implemented in the @react-navigation/native-stack with React Native Reanimated.

警告

在撰写本指南时,共享元素转换被视为实验性功能,不建议用于生产使用。

¥As of writing this guide, Shared Element Transitions are considered an experimental feature not recommended for production use.

先决条件

¥Pre-requisites

在继续本指南之前,请确保你的应用满足以下条件:

¥Before continuing this guide make sure your app meets these criteria:

最小的例子

¥Minimal example

要创建共享过渡:

¥To create a shared transition:

  1. 使用从 react-native-reanimated 导入的 Animated 组件。

    ¥Use Animated components imported from react-native-reanimated.

  2. 将相同的 sharedTransitionTag 分配给不同屏幕上的元素。

    ¥Assign the same sharedTransitionTag to elements on different screens.

  3. 在屏幕之间导航。过渡将自动开始。

    ¥Navigate between screens. The transition will start automatically.

import * as React from 'react';
import { View, StyleSheet } from 'react-native';
import {
useNavigation,
createStaticNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';

import Animated from 'react-native-reanimated';

function HomeScreen() {
const navigation = useNavigation();

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

function DetailsScreen() {
const navigation = useNavigation();

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

const RootStack = createNativeStackNavigator({
screens: {
Home: HomeScreen,
Details: DetailsScreen,
},
});

const Navigation = createStaticNavigation(RootStack);

export default function App() {
return <Navigation />;
}

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

sharedTransitionTag 是一个字符串,在单个屏幕的上下文中必须是唯一的,但必须匹配屏幕之间的元素。这个属性允许 Reanimated 识别元素并为其设置动画,类似于 key 属性,它告诉 React 列表中的哪个元素是哪个。

¥sharedTransitionTag is a string that has to be unique in the context of a single screen, but has to match elements between screens. This prop allows Reanimated to identify and animate the elements, similarly to the key property, which tells React which element in the list is which.

自定义过渡

¥Customizing the transition

默认情况下,过渡使用 withTimingwidthheightoriginXoriginYtransform 属性设置动画,持续时间为 500 毫秒。你可以轻松自定义 widthheightoriginXoriginY 属性。自定义 transform 也是可能的,但这远远超出了本指南的范围。

¥By default, the transition animates the width, height, originX, originY and transform properties using withTiming with a 500 ms duration. You can easily customize width, height, originX, and originY props. Customizing transform is also possible but it's far beyond the scope of this guide.

警告

自定义 SharedTransition API 尚未最终确定,可能会在未来版本中发生变化。

¥Custom SharedTransition API is not finalized and might change in a future release.

要自定义过渡,你需要传递除 transform 之外的所有属性。

¥To customize the transition you need to pass all the properties besides transform.

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"
sharedTransitionStyle={customTransition} // add this to both elements on both screens
/>
);
}

参考

¥Reference

你可以在 React Native Reanimated 文档 中找到完整的共享元素转换参考。

¥You can find a full Shared Element Transitions reference in the React Native Reanimated documentation.

备择方案

¥Alternatives

或者,你可以将 react-native-shared-element 库与 React 导航绑定 一起使用,后者在基于 JS 的 @react-navigation/stack 导航器中实现共享元素转换。然而,该解决方案并未得到积极维护。

¥Alternatively, you can use react-native-shared-element library with a React Navigation binding which implements Shared Element Transitions in a JS-based @react-navigation/stack navigator. This solution, however, isn't actively maintained.

react-native-navigation 还支持共享元素转换。你可以阅读更多相关内容 此处

¥The react-native-navigation also comes with support for Shared Element Transitions. You can read more about it here.