动画反应导航本机堆栈标题的问题

Cri*_*rez 6 react-native react-navigation react-native-reanimated react-native-reanimated-v2

我想要的是

我试图通过在用户向下滚动时将背景从透明更改为灰色来对反应导航本机堆栈标题进行动画处理。我正在阅读文档,它建议使用 navigation.setOptions屏幕信息进行交互。

我正在使用react-native-reanimated来捕获滚动值并在用户与屏幕交互时更改它。

问题

我正在捕获滚动值并在setOptions方法内使用它,但它不起作用,它只是不执行更改。

import React from 'react';
import {
  useAnimatedScrollHandler,
  useSharedValue,
} from 'react-native-reanimated';

const MyScreen = ({ navigation }) => {
  const scrollY = useSharedValue(0);
  const scrollHandler = useAnimatedScrollHandler({
    onScroll: (e) => {
      scrollY.value = e.contentOffset.y;
    },
  });


  React.useLayoutEffect(() => {
    navigation.setOptions({
      headerStyle: {
        backgroundColor: scrollY.value > 0 ? 'black' : 'transparent',
      },
      headerTransparent: scrollY.value === 0,
    });
  }, [ navigation, scrollY.value ]);
}
Run Code Online (Sandbox Code Playgroud)

部门

"react-native": "0.67.2",
"react-native-reanimated": "2.9.1",
"@react-navigation/native": "^6.0.6",
"@react-navigation/native-stack": "^6.2.5",
Run Code Online (Sandbox Code Playgroud)

joa*_*out 6

可以对 Native Stack 标头进行动画处理,但由于AnimatedReanimated 2 中只有组件接受动画样式,因此您可能必须为标头创建一个新组件(一个Animated.Something)...

我们可以通过使用该选项来实现此目的,该选项可以在此处header找到。

用 Expo 构建的一个简单示例:

import React from "react";
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View } from "react-native";

import { NavigationContainer, useNavigation } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";

import Animated, {
  useSharedValue,
  useAnimatedStyle,
  useAnimatedScrollHandler,
  interpolateColor,
} from "react-native-reanimated";

const Stack = createNativeStackNavigator();

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "white",
  },

  item: {
    padding: 20,
    margin: 15,
    backgroundColor: "whitesmoke",
  },

  header: {
    paddingTop: 50,
    padding: 15,
    borderColor: "whitesmoke",
    borderBottomWidth: 1,
  },

  headerTitle: {
    fontSize: 20,
    fontWeight: "bold",
  },
});

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

  const translationY = useSharedValue(0);

  const scrollHandler = useAnimatedScrollHandler((event) => {
    translationY.value = event.contentOffset.y;
  });

  const aStyle = useAnimatedStyle(() => ({
    backgroundColor: interpolateColor(
      translationY.value,
      [0, 50],
      ["white", "skyblue"],
      "RGB"
    ),
  }));

  React.useLayoutEffect(() => {
    navigation.setOptions({
      header: () => (
        <Animated.View style={[styles.header, aStyle]}>
          <Text style={styles.headerTitle}>Testing</Text>
        </Animated.View>
      ),
    });
  }, [aStyle, navigation]);

  return (
    <View style={styles.container}>
      <Animated.ScrollView onScroll={scrollHandler} scrollEventThrottle={16}>
        {Array(15)
          .fill(0)
          .map((_, index) => (
            <View style={styles.item} key={`${index}`}>
              <Text>Item {`${index}`}</Text>
            </View>
          ))}
      </Animated.ScrollView>
      <StatusBar style="auto" />
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen component={WelcomeScreen} name="Welcome" />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
Run Code Online (Sandbox Code Playgroud)

请注意,在此示例中,我们将 an 传递Animated.Viewheader选项,将动画样式 ( aStyle) 作为样式传递给它。

另外,就像您所做的那样,我用来useAnimatedScrollHandler跟踪滚动位置,并相应地插入(使用interpolateColorbackgroundColor标题(在“白色”和“天蓝色”之间,因此更容易可视化)。

将此示例上传到此Snack,以便您可以根据需要轻松测试它。

我希望这可以帮助您解决您的问题!