How to navigate to a different screen stack in a tab navigator in react navigation v6

37 Views Asked by At

I have a buttom tab navigator which has a add screen and with a tab icon component. I the tab icon component has three button. I want to navigate to a different screen when i click on the button, but it doesn't work.

type BottonSheetParams = {
  Home: undefined;
  Overview: undefined;
  Add: NavigatorScreenParams<TransactionsPrams>;
  Budget: undefined;
  Card: undefined;
};

const AppNavigator = () => {
  return (
    <BottomSheet.Navigator
      screenOptions={({ route }) => ({
        headerShown: false,
        tabBarShowLabel: false,
        tabBarIcon: ({ color, focused }) => {
          if (route.name === "Home") {
            return (
              <TabItems
                IconName="Home"
                routeName="Home"
                color={color}
                focused={focused}
              />
            );
          } else if (route.name === "Overview") {
            return (
              <TabItems
                IconName="LineChart"
                routeName="Overview"
                color={color}
                focused={focused}
              />
            );
          } else if (route.name === "Budget") {
            return (
              <TabItems
                IconName="Calculator"
                routeName="Budget"
                color={color}
                focused={focused}
              />
            );
          } else if (route.name === "Card") {
            return (
              <TabItems
                IconName="CreditCard"
                routeName="Card"
                color={color}
                focused={focused}
              />
            );
          }
        },
        tabBarStyle: styles.tabBarStyle,
        tabBarActiveTintColor: theme.colors.white,
      })}
    >
      <BottomSheet.Screen name="Home" component={Dashboard} />
      <BottomSheet.Screen name="Overview" component={Overview} />
      <BottomSheet.Screen
        name="Add"
        component={TransactionsStack}
        options={{
          tabBarLabel: "",
          tabBarShowLabel: false,
          tabBarButton: () => {
            return <AddButton />;
          },
          tabBarStyle: { display: "none" },
        }}
      />
      <BottomSheet.Screen
        name="Budget"
        component={Budget}
        options={{
          tabBarItemStyle: {
            zIndex: 1,
          },
        }}
      />
      <BottomSheet.Screen
        name="Card"
        component={Card}
        options={{
          tabBarItemStyle: {
            zIndex: 1,
          },
        }}
      />
    </BottomSheet.Navigator>
  );
};

Transaction stack

   type TransactionsPrams = {
  AddIncomeScreen: undefined;
  AddExpense: undefined;
};

const Transactions = createNativeStackNavigator<TransactionsPrams>();

const TransactionsStack = () => (
  <Transactions.Navigator
    screenOptions={{
      headerShown: false,
      presentation: "fullScreenModal",
    }}
  >
    <Transactions.Screen name="AddIncomeScreen" component={Add} />
    <Transactions.Screen name="AddExpense" component={AddExpense} />
  </Transactions.Navigator>
);

this is the add button component:

const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

const AddButton = () => {
  const plusButton = useSharedValue("0deg");

  const buttonBackgroundColor = useSharedValue(theme.colors.primary);
  const pressed = useRef(false);
  const [isPessed, setIsPessed] = useState(false);

  const handlePressed = () => {
    if (!isPessed) {
      plusButton.value = "45deg";
      buttonBackgroundColor.value = withTiming(theme.colors.tabBarNotFocused, {
        duration: 200,
      });
    } else {
      plusButton.value = "0deg";
      buttonBackgroundColor.value = withTiming(theme.colors.primary, {
        duration: 200,
      });
    }
    setIsPessed(!isPessed);
  };

  const plusIconStyle = useAnimatedStyle(() => {
    return {
      transform: [{ rotate: plusButton.value }],
      backgroundColor: buttonBackgroundColor.value,
    };
  });

  return (
    <View>
      <AnimatedPressable
        onPress={handlePressed}
        style={[styles.addStyle, plusIconStyle]}
      >
        <Plus
          color={theme.colors.white}
          size={28}
          absoluteStrokeWidth={false}
        />
      </AnimatedPressable>

      {isPessed && <ButtonOverlay isOpened={pressed.current} />}
    </View>
  );
};

export default AddButton;

this is the button overlay component:

const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

const transAddIncomeY = -150;
const transTo = 20;

const ButtonOverlay = ({ isOpened }: { isOpened: boolean }) => {
  const navigation =
    useNavigation<NativeStackNavigationProp<TransactionsPrams>>();
  const { height, width } = useWindowDimensions();

  const addIncome = useSharedValue(0);
  const addExpense = useSharedValue(0);
  const accountTransfer = useSharedValue(0);
  const plannedPayment = useSharedValue(0);
  const overlayOpacity = useSharedValue(0);
  const overlayOpacityY = useSharedValue(0);

  const handlePresentModalPress = () => {
    navigation.navigate("AddIncomeScreen");
    // console.log("add income");
  };

  const openOverlay = () => {
    addIncome.value = withTiming(0, { duration: 400 });
    addExpense.value = withTiming(0, { duration: 400 });
    plannedPayment.value = withTiming(0, { duration: 400 });
    overlayOpacity.value = withTiming(0, { duration: 100 });
    overlayOpacityY.value = withTiming(0, { duration: 50 });
  };

  const closeOverlay = () => {
    addIncome.value = withSpring(transAddIncomeY, { duration: 300 });
    addExpense.value = withSpring(transAddIncomeY, { duration: 300 });
    accountTransfer.value = withSpring(transAddIncomeY, { duration: 400 });
    plannedPayment.value = withTiming(1, { duration: 400 });
    overlayOpacity.value = withTiming(1, { duration: 80 });
    overlayOpacityY.value = withTiming(-1, { duration: 600 });
  };

  if (isOpened) {
    openOverlay();
  } else {
    closeOverlay();
  }

  const addIncomeStyle = useAnimatedStyle(() => {
    return {
      transform: [
        {
          translateY: interpolate(
            addExpense.value,
            [transAddIncomeY, transTo],
            [transAddIncomeY, 0]
          ),
        },
        {
          translateX: interpolate(
            addExpense.value,
            [transAddIncomeY, 0],
            [-130, 0]
          ),
        },
        { scale: interpolate(addIncome.value, [transAddIncomeY, 0], [1, 0]) },
      ],
      zIndex: 3,
    };
  });

  const addExpenseStyle = useAnimatedStyle(() => {
    return {
      transform: [
        {
          translateY: interpolate(
            addIncome.value,
            [transAddIncomeY, transTo],
            [-230, 0]
          ),
        },
        { scale: interpolate(addExpense.value, [transAddIncomeY, 0], [1, 0]) },
      ],
      zIndex: 3,
    };
  });

  const accountTransferStyle = useAnimatedStyle(() => {
    return {
      transform: [
        {
          translateY: interpolate(
            addExpense.value,
            [transAddIncomeY, transTo],
            [transAddIncomeY, 0]
          ),
        },
        {
          translateX: interpolate(
            addExpense.value,
            [transAddIncomeY, 0],
            [130, 0]
          ),
        },
        { scale: interpolate(addIncome.value, [transAddIncomeY, 0], [1, 0]) },
      ],
      zIndex: 3,
    };
  });

  const plannedPaymentStyle = useAnimatedStyle(() => {
    return {
      opacity: plannedPayment.value,
      zIndex: 3,
    };
  });

  const overlayStyles = useAnimatedStyle(() => {
    return {
      width,
      height,
      top: -(height / 1.12),
      left: -(width / 2.375),
      opacity: interpolate(overlayOpacity.value, [1, 0], [1, 0]),
      transform: [
        { translateY: interpolate(overlayOpacityY.value, [-150, 0], [150, 0]) },
      ],
      pointerEvents: "none",
    };
  });

  return (
    <>
      <Animated.View style={[styles.overlay, overlayStyles]} />
      <View>
        <AnimatedTransactionButton
          buttonName="ADD INCOME"
          icon="ArrowDown"
          style={addIncomeStyle}
          bgc={theme.colors.linearGreen}
          onPress={handlePresentModalPress}
        />

        <AnimatedTransactionButton
          buttonName="ADD EXPENSE"
          icon="ArrowUp"
          style={addExpenseStyle}
          bgc={theme.colors.linearRed}
          onPress={() => console.log("Add expense")}
        />

        <AnimatedTransactionButton
          buttonName="ACCOUNT TRANSFER"
          icon="Shuffle"
          style={accountTransferStyle}
          bgc={theme.colors.primary}
          onPress={() => console.log("Account transfer")}
        />

        <AnimatedPressable
          style={[styles.plannedPaymentContainer, plannedPaymentStyle]}
          onPress={() => console.log("planned payment")}
        >
          <Zap
            color={theme.colors.white}
            size={28}
            absoluteStrokeWidth={false}
          />
          <Text style={styles.plannedText}>Add planned payment</Text>
        </AnimatedPressable>
      </View>
    </>
  );
};

export default ButtonOverlay;

AnimatedTransactionButton:

const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

type AnimatedTransactionButtonProp = {
  icon: any;
  style: StyleProps;
  buttonName: string;
  bgc: string;
  onPress: () => void;
};

const AnimatedTransactionButton = ({
  buttonName,
  icon,
  style,
  bgc,
  onPress,
}: AnimatedTransactionButtonProp) => {
  return (
    <Animated.View style={[styles.buttonContainer, style]}>
      <AnimatedPressable
        onPress={onPress}
        style={[styles.defaultButtonStyle, { backgroundColor: bgc }]}
      >
        <Icon color={theme.colors.white} size={28} name={icon} />
      </AnimatedPressable>

      <Text style={styles.animatedText}>{buttonName}</Text>
    </Animated.View>
  );
};

export default AnimatedTransactionButton;

I tried this:

navigation.navigate("Transactions", { screen: "AddIncome" });

and i got this error: ERROR The action 'NAVIGATE' with payload {"name":"AddIncome"} was not handled by any navigator.

Do you have a screen named 'AddIncome'?

If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.

i tried this also and it didn't work:

navigation.navigate("AddIncome");
0

There are 0 best solutions below