Add an overlay to a react-navigation navigator - react-native

I'm trying to add an overlay (e.g. to display error popups/toasters/debug buttons etc) to a react-navigation navigator.
However I have a problem:
When I put the react navigator in a view, with the overlay on top, the react navigator either doesn't appear or is distorted in some way.
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
return <Text>Hello, Navigation!</Text>;
}
}
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
});
class SimpleAppWithOverlay extends React.Component {
render() {
return(
<View>
<View style={{position: "absolute", backgroundColor:"transparent", margin:30}}>
<Text>Some Overlay</Text>
</View>
<SimpleApp/>
</View>);
}
}
Here are two snippets showing what I mean in a live editor:
Basic react navigation setup: https://snack.expo.io/ryI4oCvQW
Same, but with an overlay attempt: https://snack.expo.io/HkSgoCDX-
You can see in the second example, the overlay appears but the underlying app is just not visible.
Can this work? How?

Changed your code a bit
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
return (
<View style={{ flex: 1 }}>
<Text>Hello, Navigation!</Text>
</View>
)
}
}
class SimpleAppWithOverlay extends React.Component {
render() {
return (
<View style={{flex: 1}}>
<SimpleApp />
<View style={{ position: "absolute", backgroundColor: 'rgba(255,0,0,0.4)', top: 0, bottom: 0, left: 0, right: 0 }}>
<Text style={{ paddingTop: 8 }}>Some Overlay</Text>
</View>
</View>
);
}
}
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
});
AppRegistry.registerComponent('overlayapp', () => SimpleAppWithOverlay);
You should note that position: 'absolute' is only positioning relative to the parent not absolutely absolute like in css.
If you want to overlay above the navigationBar you can probably do something similar with navigationOptions.headerRight.

Related

Unable to get tab bar from react-navigation working

I want to show tab bar in my react-native app using react-navigation library. I've tried code from an example provided in the documentation. However, when I run the code on iOS simulator the screen appears to be blank, tab bar doesn't load.
Here's my code so far,
TabNavigator.js
import React from 'react';
import { Text, View } from 'react-native';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
);
}
}
class SettingsScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
}
const TabNavigator = createBottomTabNavigator(
{
Home: HomeScreen,
Settings: SettingsScreen,
},
{
initialRouteName: "Home"
}
);
export default createAppContainer(TabNavigator);
App.js
import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { createBottomTabNavigator } from 'react-navigation';
import TabNavigator from './components/TabNavigator';
const App = () => {
return (
<View>
<TabNavigator />
</View>
);
};
export default App;
Looking at the App.js code, you forgot to put flex:1 to the view, it's one of the common mistakes that react-navigation tells about in his documentation.
const App = () => {
return (
<View style={ { flex:1} }>
<TabNavigator />
</View>
);
};
Source: https://reactnavigation.org/docs/en/common-mistakes.html#wrapping-appcontainer-in-a-view-without-flex

Add padding to a custom contentComponent for a DrawerNavigator to avoid overlaying the status bar

When using a basic DrawerNavigator, there is proper paddingTop that avoids overlaying content over the status bar; however, when adding a custom contentComponent, the padding is not there. Code: https://github.com/myplaceonline/testreactexpo/tree/drawermargin
Without custom contentComponent on Android:
With custom contentComponent on Android:
I can add some explicit margin, but what value should I choose? I'm already using SafeAreaView, but I believe that's only for iOS.
Here's the code. Comment the contentComponent: CustomDrawerContentComponent, line to see the working view.
import React from 'react';
import { SafeAreaView, ScrollView, Text, View } from 'react-native';
import { createAppContainer, createDrawerNavigator, createStackNavigator, DrawerItems } from 'react-navigation';
class TestScreen extends React.Component {
static navigationOptions = {
title: "Test",
};
render() {
return (
<View style={{flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Test</Text>
</View>
);
}
}
const CustomDrawerContentComponent = props => (
<SafeAreaView style={{flex: 1}} forceInset={{ top: "always", horizontal: "never" }}>
<ScrollView>
<DrawerItems {...props} />
</ScrollView>
</SafeAreaView>
);
export default AppDrawer = createAppContainer(
createDrawerNavigator(
{
DrawerTest: {
screen: createStackNavigator(
{
Test: TestScreen
},
),
navigationOptions: {
drawerLabel: "Test",
}
},
},
{
contentComponent: CustomDrawerContentComponent,
}
)
);
<div data-snack-id="#git/github.com/myplaceonline/testreactexpo#drawermargin" data-snack-platform="ios" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#fafafa;border:1px solid rgba(0,0,0,.08);border-radius:4px;height:505px;width:100%"></div>
<script async src="https://snack.expo.io/embed.js"></script>
Solved with:
import Constants from 'expo-constants';
<ScrollView style={{paddingTop: Constants.statusBarHeight}}>

Trying to navigate to another screen based on text click, but got an error "undefined is not an object (evaluation navigate.navigateToScreen)"

I've been trying to navigate from Text to another screen but this error pops up, can anyone please help
This is a testing sheet for a bigger problem I have posted here Navigate when clicking on image doesn't work , I am trying to structure my code to navigate from an Image to a page. Thanks for helping
import React from 'react';
import { AppRegistry, StyleSheet, View, Image, TouchableOpacity, Text } from "react-native";
import { createAppContainer, createStackNavigator, StackActions, NavigationActions } from 'react-navigation'; // Version can be specified in package.json
import AddDocScreen from './Menu/AddDocScreen'
export default class Mock extends React.Component {
render() {
const navigate = this.props.navigation
return (
<View style={styles.container}>
<TouchableOpacity
onPress={() => navigate.navigateToScreen(navigationAction)}>
<View><Text>Click Me</Text></View>
</TouchableOpacity>
</View>
)
}
}
const navigationAction = NavigationActions.navigate({
routeName: 'AddDocSreen',
})
function navigateToScreen(navigationAction) {
() => {
return navigationAction
}
}
const doc = createStackNavigator({
AddDocScreen: { screen: AddDocScreen },
});
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'rgba(215,215,215,1)',
alignItems: 'center',
justifyContent: 'center',
},
})
Use it like this:
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import AddDocScreen from './Menu/AddDocScreen'
class Mock extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center',backgroundColor: 'rgba(215,215,215,1)'}}>
<Text>Home Screen</Text>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Details')}>
<View><Text>Click Me</Text></View>
</TouchableOpacity>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Mock: Mock,
AddDocScreen: AddDocScreen,
{
initialRouteName: 'Mock',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}

ImageBackground component as a container of react-navigation router hiding all child components

I want to set a background image to all of the screens in my react native application,
I am using ImageBackground component on the top level of my components tree like that:
export default class App extends React.Component {
render(){
return(
<View style={{ flex: 1 }}>
<ImageBackground source={require('../assets/app-bg.png')} style={{width: '100%', height: '100%', flex: 1, zIndex: 0, resizeMode: 'cover' }}>
<Router />
</ImageBackground>
</View>)
}
}
and I have the child component which is the router from react-navigation
like that:
class LandingPage extends React.Component {
render(){
return(
<View style={{flex: 1, zIndex: 999}}>
<Text>here is landing page></Text>
</View>
)
}
}
const RouterNavigator = createAppContainer(createStackNavigator({
Landing: {
screen: Landing,
navigationOptions:{
header: null
}
}
}
export default class Router extends React.Component {
render() {
return <RouterNavigator style={{flex: 1}}/>
}
}
the problem is that the background image is being rendered but the child component LandingPage is being hidden even though it is being rendered too!
Just have a look at this example.Does this help you acheive what you were
trying to.
import * as React from 'react';
import { Text, View, StyleSheet, ImageBackground } from 'react-native';
import { Constants } from 'expo';
import AssetExample from './components/AssetExample';
import { createAppContainer, createStackNavigator } from 'react-navigation';
import { Card } from 'react-native-paper';
class LandingPage extends React.Component {
render() {
return (
<View>
<Text>here is landing page</Text>
</View>
);
}
}
const RouterNavigator = createAppContainer(
createStackNavigator(
{
LandingPage: {
screen: LandingPage,
navigationOptions: {
header: null,
},
},
},
{
mode: 'card',
transparentCard: true,
cardStyle: { backgroundColor: 'transparent' },
transitionConfig: () => ({
containerStyle: {
backgroundColor: 'transparent',
},
}),
initialRouteName: 'LandingPage',
}
)
);
export default class App extends React.Component {
render() {
return (
<ImageBackground
source={require('./bgimage.jpeg')}
style={{
flex: 1,
}}>
<RouterNavigator />
</ImageBackground>
);
}
}

react-native navigation in Flatlist component over multiple files

I am using react-navigation for navigation and right now i am trying to navigate between Screens using my flatlist. I want it so that when i click on an item in the list that i get send to the Details screen, but whenever i press on an item in the list with this code, nothing happens. I tried to pass the navigation property from the Homescreen component to the MyListItem Component but then i get undefined is not an Object error.
However, i have a Test TouchableOpacity in my Homescreen Component and if i click on that, i can navigate to the Details screen (See "Test" Text in Homescreen Component).
I think i did something wrong with the navigation property, but i have been searching everywhere and have not found a solution.
This is my App.js file with the StackNavigator:
import React from 'react';
import { createStackNavigator } from 'react-navigation'
import HomeScreen from './screens/HomeScreen'
import DetailScreen from './screens/DetailScreen'
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailScreen,
},
{
initialRouteName: 'Home',
navigationOptions: {
header: null,
},
}
);
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
This is my HomeScreen file where the Problem is happening:
import React from 'react'
import { StyleSheet, Text, View, TouchableOpacity, StatusBar,
FlatList, Image } from 'react-native'
import Data from '../data/Data'
class MyListItem extends React.Component {
render() {
return(
<View style={styles.container}>
<TouchableOpacity
onPress={this.props.handleOnPress}
>
<View style={{ flexDirection: 'row', heigth: 100, width: 100 }}>
<View>
<Image style={{ height: 50, width: 50, resizeMode: 'contain' }} source={require('../res/icon.png')} />
</View>
<View style={{ justifyContent: 'center' }}>
<Text>
{this.props.item.name}
</Text>
</View>
</View>
</TouchableOpacity>
</View>
);
}
}
class HomeScreen extends React.Component {
handleOnPress = () => {
this.props.navigation.navigate('Details')
}
render() {
return (
<View>
<StatusBar hidden={true} />
<TouchableOpacity
onPress={() => this.props.navigation.navigate('Details')}
>
<Text>Test</Text>
</TouchableOpacity>
<FlatList
data={Data}
renderItem={({ item }) =>
<MyListItem
item={item}
onPress={this.handleOnPress}
/>
}
/>
</View>
);
}
}
export default HomeScreen;
Ps: I run the Code on an Android emulator.
Edit: edited answer suggestion into code
Might be a typo mistake but, you try to navigate to navigate('Details') when you declared your screen as Detail
{
Home: HomeScreen,
Detail: DetailScreen, <----
},