I'm really new to RN and just trying out stuffs. Been trying to achieve lock and unlock drawer items dynamically based on certain condition using drawerLockMode but not working.
global.navigationOptions = {
drawerLockMode: 'locked-open'
}
const DrawerNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen
},
NewScreen: {
screen: NewScreen
}
},
navigationOptions = global.navigationOptions);
In another part, trying to change navigationOptions.drawerLockMode based on random generated number > threshold to change the lock/unlock status. I know I'm probably in the wrong direction. Can anyone please advice?Thanks in advance
Related
I am trying to hide app content when the user tries to navigate away from the app, like how banking apps or outlook works. I am using appstate inactive for ios, and appstate blur+focus for android. This works on Android when the user pulls down the notification panel or swipes up to multitasking tray or home through a gesture.
However, if the android phone has soft buttons for navigation instead of gestures, the app doesnt show the security screen on blur. I suppose react native loses control of the app too soon for that to happen. The blur event is still triggered, but the UI remains unchanged.
I have a useEffect in a custom hook that changes the state on blur, which triggers the UI update;
const [appStateVisible, setAppStateVisible] = useState(true);
const appState = useRef(AppState.currentState);
useEffect(() => {
const androidFocusSubscription =
Platform.OS === 'android' &&
AppState.addEventListener('focus', () => {
setAppStateVisible(true);
});
const androidBlurSubscription =
Platform.OS === 'android' &&
AppState.addEventListener('blur', () => {
setAppStateVisible(false);
});
return () => {
if (androidFocusSubscription && androidBlurSubscription) {
androidFocusSubscription.remove();
androidBlurSubscription.remove();
}
};
}, []);
return appStateVisible;
And then on App.tsx, I am calling this hook to decide whether to show the security image instead of the actual app content.
The alternative would be to use FLAG_SECURE in the java code to show a white screen when the app isnt active, but I want to show a custom screen with the app logo instead of a white screen.
Any help would be greatly appreciated. Thank you.
I'm hoping this is a known problem as I can't provide much to go on to get help solving it.
I'm using react-navigation for my app with the following setup:
AppContainer
Splash Screen
Setup Screen (A stack navigator)
Main screen (A stack navigator)
When my app starts it goes to the splash screen which decides if this is the first time running or not and depending on this decision calls this.props.navigation.navigate() with either main screen or setup screen.
So far this all works and is fairly standard.
When my app is launched for the first time the user is sent to the setup screen where they navigate through a series of screens entering data and selecting a next button to proceed to the next screen. This is where the problem occur. My first screen simply has some text and a next button (which is a regular button component) which when clicked calls this.props.navigation.push('nextviewname', {data: data}) to move to the next view.
The next view contains a textinput as well as back and next buttons which is where I'm having problems. When I reach this screen after freshly installing a release version of my app onto my Android X phone none of the inputs work. I can't:
Click next of back
Click the back arrow in the top left that is part of the header
Click the text input (the cursor does briefly show up in the text input but the keyboard never appears)
Click the hardware back key
On very rare occasions some of the above does work (e.g. the text input will sometimes work) and sometimes I'll even make it to the next step of my setup but it's rare that I make it all the way through
Weirdly this all works when I'm debugging my app on my phone.
Update: I've just tested on an Android 9 emulator and I'm getting the same issue.
Update 2: This is getting weird, when the app is in a broken state I can still bring up the react native debug menu however when I click Toggle Inspector nothing happens (i.e. I don't get the inspector UI). It's looking like this is somehow breaking everything.
Has anyone seen/solved this issue before? At the moment it's effectively made my app useless.
Update 3: Some code to hopefully make things clearer:
const SetupUser = createStackNavigator(
{
SetupUser: WelcomeScreen,
SetupName: UserName,
SetupCurrentWeight: CurrentWeight,
SetupGoalWeight: GoalWeight,
SetupGoalDate: GoalDate,
Summary: Summary,
LogWeight: LogWeight,
},
{
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#001830',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
},
);
const MainApp = createStackNavigator(
{
LogWeight: LogWeight,
LogWeightSummary: LogWeightSummary,
},
{
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#001830',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
},
);
export default createAppContainer(
createSwitchNavigator(
{
MainApp: MainApp,
SplashScreen: SplashScreen,
SetupUser: SetupUser,
},
{
initialRouteName: 'SplashScreen',
},
),
);
In getting this code snippit together (I've removed the tab navigator as the error is still there even without it) I think I've managed to track down the source of the issue however I'm still not sure how to fix it. The first view loaded is the splash screen which looks like this:
export default class SplashScreen extends React.Component {
constructor(props) {
super(props);
GoBinder.verifyDatabase()
.then(GoBinder.getLastUser())
.then(user => {
this.props.navigation.navigate(
user.user == null ? 'SetupUser' : 'MainApp',
);
})
.catch(error => {
GoBinder.toast('Error while checking initial user state: ' + error);
});
}
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}
In the above code, GoBinder.verifyDatabase() and GoBinder.getLastUser() are calls to native code which perform some database operation to get things setup and check to see if there are any existing users. I believe the issue is this.props.navigation.navigate is firing too quickly which is causing react-navigation to load the next screen but get messed up in the process.
I've tried following the suggestions in this post https://www.novemberfive.co/blog/react-performance-navigation-animations about moving blocking code into InteractionManager.runAfterInteractions under componentDidMount however this made no difference. However, it I manually trigger the move to the new screen using a button everything works correctly so its really looking like the act of programatically changing screens is messing things up.
Update 4:
Looks like I jumped the gun a bit, its still freezing up a fair bit, moving my answer into an update:
So I'm not sure if this is the best solution but I have found a workaround. I am now calling my database code in InteractionManager.runArfetInteraction() as suggested in https://www.novemberfive.co/blog/react-performance-navigation-animations. I am then calling setState with the result of the DB functions to store the result. Finally, I am using a callback on setState to trigger the actual navigation. My complete working code is:
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
GoBinder.verifyDatabase()
.then(
GoBinder.getLastUser().then(user => {
this.setState(
{
user: user.user,
},
() => {
this.props.navigation.navigate(
this.state.user == null ? 'SetupUser' : 'MainApp',
);
},
);
}),
)
.catch(error => {
GoBinder.toast('Error while checking initial user state: ' + error);
});
});
}
Thanks for your help
I have a react native project and i use react-navigations bottom tab navigation in one of the screens.
My question is can i dynamically change one of the icons in it based on which screen am i located ?
For an example i want the middle icon to be dynamic and different for all of the other tabs and when user press some tab i want that icon to change and to have unique functionality.
Do i need to set a callback and pass in every screen that has access and after that callback to re-render the navigator ? - If so will i lose all of the cached & mounted stuff because of the re-render ?
Looking for an optimal solution. Any answer is appreciated.
Thanks.
To do this you have to customize the tab a bit, to do so you need to use the custom
defaultNavigationOptions in createBottomTabNavigator. defaultNavigationOptions takes in a function of a React component where you get a prop such as focused, tintColor, you can do some manipulation using this. If the tab is focused you will get a true value based on that you can change your icon.
For example:
const customTabs = ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
if (routeName === 'PageOne') {
return <View>{focused ? <Icon name='focused' /> : <Icon name='unfocused' /> }</View>
} else if (routeName === 'PageTwo') {
return <Text>{routeName} One</Text>
} else if (routeName === 'PageThree') {
return <Text>{routeName} One</Text>
}
}
});
I have added a small example, couldn't figure out how to add a icon to it, so just changing the text, you can replace them with Icon, this will work.
https://snack.expo.io/#subkundu/icon-focused
Let me know if this works. Happy coding. :)
I want to implement Bottom Tab Navigation.So I have done using react native Navigation.But,I need to load the data to the Bottom Tab Navigation that gets the data from json file from server.As of now,I have only implemented the static data and components.Can anyone guide me on how to implement this?
const SettingsStack = createStackNavigator({
Settings: { screen: SettingsScreen }
});
const MoreStack = createStackNavigator({
More: { screen: MoreScreens }
});
export default createBottomTabNavigator(
{
Home: { screen: HomeStack },
Search: { screen: searchStack },
Downloads: { screen: DownloadStack },
Settings: { screen: SettingsStack },
More: { screen: MoreStack }
},
By design react-navigation does not support dynamic route, but you can instead make a higher order function that receive the json data you want as the parameter and them return the navigator as you want. The trade off is that the whole navigation stack will be reset.
I had the best experience/results using react-native-navigation. It uses native components, so you get much better performance and feel. And you can set up bottom tab navigation easily.
Also, this piece is a really good summary of what's out there.
Is there a way to add a clickable icon along with StackNavigator objects?
This is a working code and it will show a "createBottomTabNavigator" with only one icon that will lead to "OtherScreen" on press.
const OtherStack = createStackNavigator({
Other: OtherScreen,
});
OtherStack.navigationOptions = {
tabBarLabel: 'Other',
tabBarIcon: ({
focused
}) => (
<TabBarIcon focused={focused} name='archive' />
),
};
export default createBottomTabNavigator({
OtherStack
});
I would like to add a share icon to the same "createBottomTabNavigator" so it will be aligned with all other icons but I don't want it to lead to a different screen. I just want it to open a share dialog.
I can't find a solution for this. Is it possible at all? Can someone help please?
You can add a button to the tab bar that doesn't lead to another screen by overriding tabBarOnPress for the route. Here's an example: https://snack.expo.io/#notbrent/playful-almond
The important part is here:
Placeholder: {
screen: () => null,
navigationOptions: {
tabBarOnPress: ({ navigation, defaultHandler }) => {
// don't call default handler!
alert('pressed placeholder!');
},
},
},