zoontek / react-native-bars

Components to control your app status and navigation bars.
MIT License
292 stars 16 forks source link

Add setBarStyle method #5

Closed 1280103995 closed 2 years ago

1280103995 commented 2 years ago

Why it is needed?

Sometimes people don't want to update barStyle by rendering components. Therefore, providing static methods can meet these needs.

Currently I switch screens back and forth in the TabBar of react-navigation, and the barStyle has not changed (rendered by components). Therefore, I want to change the barStyle in a way similar to navigation.addListener('focus').:grin:

Possible implementation

Add the setBarStyle method to the component.

StatusBar.tsx

export class StatusBar extends React.Component<StatusBarProps> {
  private static propsStack: StatusBarProps[] = [];
  private static immediate: NodeJS.Immediate | null = null;
  private static mergedProps: StatusBarProps | null = null;

  static setBarStyle(props: StatusBarProps) {
    const animated = props.animated || false;
    const oldProps = StatusBar.mergedProps;
    if ((props.barStyle === "light-content" || props.barStyle === "dark-content")
      && oldProps?.barStyle !== props.barStyle)
    {
      if (Platform.OS === "android") {
        NativeModule?.setStatusBarStyle(props.barStyle);
      } else {
        RNStatusBar.setBarStyle(props.barStyle, animated);
      }
      /** Is it necessary ?*/
      // StatusBar.mergedProps = {
      //   ...props,
      //   barStyle: "light-content",
      // };
    }
  }

  ..............
}

NavigationBar.tsx

export class NavigationBar extends React.Component<NavigationBarProps> {
  private static propsStack: NavigationBarProps[] = [];
  private static immediate: NodeJS.Immediate | null = null;
  private static mergedProps: NavigationBarProps | null = null;

  static setBarStyle(props: NavigationBarProps) {
    const oldProps = NavigationBar.mergedProps;
    if (props.barStyle === "light-content" || props.barStyle === "dark-content") {
      if (isSupportedPlatform && oldProps?.barStyle !== props.barStyle) {
        NativeModule?.setNavigationBarStyle(props.barStyle);
      }
      /** Is it necessary ?*/
      // NavigationBar.mergedProps = {
      //   ...props,
      //   barStyle: "light-content",
      // };
    }
  }

  .................
}

Code sample

App.js

import React, {useEffect} from 'react';
import {Text, View} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {NavigationBar, StatusBar} from './src/ts'; //Change the code yourself

function HomeScreen({navigation}) {
  useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      StatusBar.setBarStyle({barStyle: 'light-content'});
      NavigationBar.setBarStyle({barStyle: 'light-content'});
    });
    return () => {
      unsubscribe();
    };
  }, [navigation]);

  return (
    <View
      style={{
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'pink',
      }}>
      <Text>light-content</Text>
    </View>
  );
}

function ProfileScreen({navigation}) {
  useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      StatusBar.setBarStyle({barStyle: 'dark-content'});
      NavigationBar.setBarStyle({barStyle: 'dark-content'});
    });
    return () => {
      unsubscribe();
    };
  }, [navigation]);

  return (
    <View
      style={{
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'white',
      }}>
      <Text>dark-content</Text>
    </View>
  );
}

const Tab = createBottomTabNavigator();
const TabStack = () => {
  return (
    <Tab.Navigator
      screenOptions={{
        headerStyle: {
          backgroundColor: 'green',
        },
        tabBarStyle: {
          backgroundColor: 'pink',
        },
      }}>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Profile" component={ProfileScreen} />
    </Tab.Navigator>
  );
};

const Stack = createStackNavigator();
const AppNavigator = () => {
  return (
    <Stack.Navigator
      screenOptions={{
        headerShown: false,
      }}>
      <Stack.Screen name={'Tab'} component={TabStack} />
    </Stack.Navigator>
  );
};

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

"dependencies": {
    "@react-native-masked-view/masked-view": "^0.2.6",
    "@react-navigation/bottom-tabs": "^6.0.9",
    "@react-navigation/native": "^6.0.6",
    "@react-navigation/stack": "^6.0.11",
    "prop-types": "^15.7.2",
    "react": "17.0.2",
    "react-native": "0.66.3",
    "react-native-gesture-handler": "^1.10.3",
    "react-native-safe-area-context": "^3.3.2",
    "react-native-screens": "^3.9.0"
  }
zoontek commented 2 years ago

Use push / replace / pop stackEntry: https://github.com/zoontek/react-native-bars#statusbarpushstackentry

This does exactly what you want.

1280103995 commented 2 years ago

Use push / replace / pop stackEntry: https://github.com/zoontek/react-native-bars#statusbarpushstackentry

This does exactly what you want.

I tried these methods, but they didn't work.

zoontek commented 2 years ago

They are used internally by the components, check usage: https://github.com/zoontek/react-native-bars/blob/3e77d45b72e527e71e35cf43eac1eb4165c5a0ca/src/StatusBar.tsx#L81

1280103995 commented 2 years ago

I don't know why it was changed to light-content at the end. When I commented out barStyle, the pushStackEntrymethod worked normally.

// Update the current props values.
StatusBar.mergedProps = {
   ...lastEntry,
   barStyle: "light-content",
};

Same in NavigationBar.

zoontek commented 2 years ago

Indeed, it's was a default for when lastEntry was null (const mergedProps = { barStyle: "light-content", ...lastEntry }). I commited something stupid, sorry (not even the right order). Just published the 1.1.1 that fix that.

1280103995 commented 2 years ago

Indeed, it's was a default for when lastEntry was null (const mergedProps = { barStyle: "light-content", ...lastEntry }). I commited something stupid, sorry (not even the right order). Just published the 1.1.1 that fix that.

Great!