2

I am practicing and new in React native and I really like React navigation.

I have been playing around react navigation and made custom settings like ErrorBoundary which it works fine.

I created one component and named it settings, from that settings component user can toggle the button go to Dark mode.

I didn't find in the documentation how to change the app's dark mood. Can any please help me out, How to change dark mood from child component?

This is my router component. Where I navigate the component.

import { Ionicons } from "@expo/vector-icons";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { useNavigation } from "@react-navigation/native";
import React, { useContext } from "react";
import { Button, Text, View } from "react-native";
import { ThemeContext } from "styled-components";
import ErrorBoundary from "../components/errorBoundaries";
import ITheme from "../themes/types";
import IssuesRouter from "./issues/components/router";
import Settings from "./settings/Settings";
import StyleGuide from "./styleGuide";
import Itinerary from "./tasks/views/itinerary";

const tabIcon = ({ focused, color, size, route }: any) => {
  let iconName;
  if (route.name === `Tasks`) {
    iconName = focused
      ? `ios-checkmark-circle`
      : `ios-checkmark-circle-outline`;
  } else if (route.name === `Issues`) {
    iconName = focused ? `ios-warning` : `ios-warning`;
  } else if (route.name === `History`) {
    iconName = focused ? `ios-list-box` : `ios-list`;
  } else if (route.name === `Settings`) {
    iconName = focused ? `ios-settings` : `ios-settings`;
  }
  return <Ionicons name={iconName} size={size} color={color} />;
};

const ApplicationRouter = () => {
  const Tab = createBottomTabNavigator();
  const theme: ITheme = useContext(ThemeContext);

  const HomeScreen = () => { 
    const { navigate } = useNavigation();
    return (
      <View
        style={{
          flex: 1,
          backgroundColor: `pink`,
          justifyContent: `center`,
          alignItems: `center`
        }}
      >
        <Text>Home!</Text>
        <Button onPress={() => navigate(`Tasks`)} title="Open Modal" />
      </View>
    );
  };

  return (
    <ErrorBoundary id="ApplicationRouter">
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: i =>
            tabIcon({
              ...i,
              route
            })
        })}
        tabBarOptions={{
          activeTintColor: theme.linkColor,
          inactiveTintColor: theme.linkColorInactive,
          style: {
            paddingTop: 10,
            borderTopWidth: 0,
            backgroundColor: theme.backgroundColorAlt2
          }
        }}
        lazy={false}
      >
        <Tab.Screen name="Tasks" component={Itinerary} />
        <Tab.Screen name="Issues" component={IssuesRouter} />
        <Tab.Screen name="History" component={HomeScreen} />
        <Tab.Screen name="Settings" component={Settings} /> //THIS IS MY SETTING COMPONENT WHERE I WANT CHANGE MY DARK MOOD 
        <Tab.Screen name="Style guide" component={StyleGuide} />
      </Tab.Navigator>
    </ErrorBoundary>
  );
};

export default ApplicationRouter;

This is my setting component

import React, { useState } from "react";
import { StyleSheet, Switch, View } from "react-native";

export default function App() {
  const [isEnabled, setIsEnabled] = useState(false);
  const toggleSwitch = () => setIsEnabled(previousState => !previousState);

  return (
    <View style={styles.container}>
      <Switch
        trackColor={{ false: "#767577", true: "#81b0ff" }}
        thumbColor={isEnabled ? "#f5dd4b" : "#f4f3f4"}
        ios_backgroundColor="#3e3e3e"
        onValueChange={toggleSwitch}
        value={isEnabled}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center"
  }
});
Federico Baù
  • 6,013
  • 5
  • 30
  • 38
Krisna
  • 2,854
  • 2
  • 24
  • 66

1 Answers1

1

I see is an old question, nevertheless I want to answer in case someone is browsing this issue.

At the current version of react-native- navigation (6*.0) is very simple to set up a theme manager the whole App with few boiler plate code

NOTE!!!:

This pacakges must be installed in order for this to work (All all part of React-navigation):

npm install @react-navigation/native
# 2 Main dependencie
npm install react-native-screens react-native-safe-area-context
# 3 Addittional Package (Stack)
npm install @react-navigation/native-stack react-native-gesture-handler

# 4 Additional Dependency:
npm install @react-navigation/stack react-native-gesture-handler

FULL WORKING CODE WITH MINIMUN CODE

import * as React from 'react';
import { Button, View, Text, TouchableOpacity } from 'react-native';
import {NavigationContainer,DefaultTheme, DarkTheme,useTheme,} from '@react-navigation/native';  // IMPORT THEMES HERE!!! 
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function SettingsScreen({ route, navigation }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Settings Screen</Text>
      <Button
        title="Go to Profile"
        onPress={() => navigation.navigate('Profile')}
      />
    </View>
  );
}

function HomeScreen({ navigation }) {
  const { colors } = useTheme();  // USE THIS In order to get the Current Themes used
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Home Screen</Text>
        <TouchableOpacity style={{ backgroundColor: colors.card }}>
          <Text style={{ color: colors.text }}>Button!</Text>
        </TouchableOpacity>
      <Button
        title="Go to Settings"
        onPress={() => navigation.navigate('Settings')}
      />
    </View>
  );
}

const Stack = createNativeStackNavigator();

export default function App() {
  return (
      <NavigationContainer theme={ DarkTheme  }> // HERE THE KEY PART, Just add the Theme and the Whole App uses it (a part of text)  
        <Stack.Navigator  initialRouteName="Home">
          <Stack.Screen name="Home" component={HomeScreen} />
          <Stack.Screen name="Settings" component={SettingsScreen} />
        </Stack.Navigator>
      </NavigationContainer>
  );
}

EXPLANATION

  1. Import this

    import {NavigationContainer,DefaultTheme, DarkTheme,useTheme,} from '@react-navigation/native'; // IMPORT THEMES HERE!!!

  2. On the NavigationContainer add prop theme

     <NavigationContainer theme={ DarkTheme  }> 
    

Note that a theme must follow this Javasrict Object Structure:

const MyTheme = {
  dark: false,
  colors: {
    primary: 'rgb(255, 45, 85)',
    background: 'rgb(242, 242, 242)',
    card: 'rgb(255, 255, 255)',
    text: 'rgb(28, 28, 30)',
    border: 'rgb(199, 199, 204)',
    notification: 'rgb(255, 69, 58)',
  },
};
  1. Access the current selected Theme with useTheme function. The texts for instance don't get updated and you wouold need to set up manually

    const { colors } = useTheme();  // USE THIS In order to get the Current
    

    // Use it like this
    <Text style={{ color: colors.text }}>Button!

**By the way, this is how the DefaultThem DarkTheme Objects are:

// DEFAULT LIGHT THEME
const DefaultTheme = {
    dark: false,
    colors: {
        primary: 'rgb(0, 122, 255)',
        background: 'rgb(242, 242, 242)',
        card: 'rgb(255, 255, 255)',
        text: 'rgb(28, 28, 30)',
        border: 'rgb(216, 216, 216)',
        notification: 'rgb(255, 59, 48)',
    },
};

// DEFAULT DARK THEME
const DarkTheme = {
    dark: true,
    colors: {
        primary: 'rgb(10, 132, 255)',
        background: 'rgb(1, 1, 1)',
        card: 'rgb(18, 18, 18)',
        text: 'rgb(229, 229, 231)',
        border: 'rgb(39, 39, 41)',
        notification: 'rgb(255, 69, 58)',
    },
};

Documentation

Federico Baù
  • 6,013
  • 5
  • 30
  • 38
  • This is very helpful, thanks. Note that this works - for the most part - on React Navigation 5.x as well. I found it tricky to get the tabbar labels and icons to use theme colors, and this solved it! – Ganberry Aug 24 '22 at 20:02