У меня есть прямоугольник внутри экрана React Native Navigation, который я хочу анимировать каждый раз, когда пользователь нажимает на этот конкретный экран. Теперь анимация воспроизводится только один раз при первом рендеринге приложения. Я видел несколько решений, которые сработали для других людей для такого рода проблем, но ни одно из них не сработало для меня — приложение не перерисовывается при нажатии. Что я делаю неправильно?
SettingsScreen.js (анимация, которая должна перерисовываться при переключении экрана)
const { width } = Dimensions.get("screen");
const SettingsScreen = ({navigation}) => {
const isFocused = useIsFocused();
return (
<FlatList
contentContainerStyle = {style.barContainer}
data = {[1, 2, 3, 4, 5]}
keyExtractor = {(_, index) => index.toString()}
renderItem = {() => (
<ProgressBar isFocused = {isFocused} navigation = {navigation} />
)}
></FlatList>
);
};
const ProgressBar = ({ navigation, isFocused }) => {
const barWidth = React.useRef(new Animated.Value(0)).current;
console.info(barWidth);
const finalWidth = width / 2;
React.useEffect(() => {
const listener = navigation.addListener("focus", () => {
Animated.spring(barWidth, {
toValue: finalWidth,
bounciness: 10,
speed: 2,
useNativeDriver: false,
}).start();
});
return listener;
}, [navigation]);
return (
<View style = {style.contentContainer}>
<Animated.View style = {[style.progressBar, { width: barWidth }]} />
</View>
);
};
MainContainer.js (где настраивается вся навигация)
const profileName = "Profile";
const detailsName = "Details";
const settingsName = "Settings";
const profileNameFR = "P";
const detailsNameFR = "D";
const settingsNameFR = "S";
const Tab = createBottomTabNavigator();
export default function MainContainer() {
const { locale } = useContext(LanguageContext);
return (
<NavigationContainer>
<Tab.Navigator
screenOptions = {({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
let rn = route.name;
if (rn === profileName || rn === profileNameFR) {
iconName = focused ? "person" : "person-outline";
} else if (rn === detailsName || rn === detailsNameFR) {
iconName = focused ? "list" : "list-outline";
} else if (rn === settingsName || settingsNameFR) {
iconName = focused ? "settings" : "settings-outline";
}
return <Ionicons name = {iconName} size = {size} color = {color} />;
},
tabBarActiveTintColor: "tomato",
inactiveTintColor: "grey",
tabBarStyle: { padding: 10, height: 60 },
tabBarLabelStyle: { paddingBottom: 10, fontSize: 10 },
style: { padding: 10 },
})}
>
"@react-navigation/bottom-tabs": "^6.4.0", "@react-navigation/native": "^6.0.13", "@react-navigation/stack": "^6.3.4",
Это происходит потому, что FlatList является PureComponent, а это означает, что он не будет повторно отображаться, если props
останется прежним. Так что в этом случае попробуйте использовать useIsFocused
хук внутри SettingsScreen
компонента и передать его ProgressBar
в качестве реквизита.
Внутри экрана настроек:
const isFocused = useIsFocused();
...
<FlatList
...
renderItem = {() => <ProgressBar isFocused = {isFocused} />}
Также не рекомендуется использовать хук useIsFocused
, потому что это приведет к ненужному повторному рендерингу вашего компонента много раз. Вместо этого вы можете использовать прослушиватель событий для прослушивания события «фокус», например:
React.useEffect(() => {
const listener = navigation.addListener('focus', () => {
Animated.spring(barWidth, {
toValue: finalWidth,
bounciness: 10,
speed: 2,
useNativeDriver: false,
}).start();
});
return listener;
}, [navigation])
Мне трудно понять, как именно работает поддержка isFocused. Кроме того, он перерисовывает страницу несколько раз при смене экрана, но значение barWidth остается прежним, поэтому оно остается прежним, потому что анимация использует хук useRef (согласно моему пониманию, при повторном рендеринге оно должно быть установлено обратно на 0)? Спасибо за ответ, но проблема для меня все еще остается. Я обновил свой код в основном сообщении.
Я отмечаю это как правильный ответ, потому что это выглядит правильным методом повторной визуализации экрана при нажатии, что на самом деле было основным вопросом.
Какую версию реактивной навигации вы используете?