adjusting Switch and Icon in stack header on react-navigation - react-native

I was trying to put an Switch and an Icon on header created with stack navigation from react navigation. the problem I am facing is that adjusting the switch and icon accordingly next to each other. I tried different alternatives but still I am unable to adjust them. I wanted to show on the header a text in the center; Home for instance, and show also a switch and icon on the right of the header next to each other (switch and icon). I will highly appreciate any help of how Can I do this? Here I am sharing my code trying to do it.
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* #format
* #flow strict-local
*/
import React, {useState} from 'react';
import {StatusBar, View, TouchableOpacity} from 'react-native';
import {
NavigationContainer,
DarkTheme as navigationDarkTheme,
DefaultTheme as navigationDefaultTheme,
useTheme
} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {
DarkTheme as PaperDarkTheme,
Provider as PaperProvider,
DefaultTheme as PaperDefaultTheme,
Text,
Title,
TouchableRipple,
Switch,
} from 'react-native-paper';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
const customDarktheme = {
...PaperDarkTheme,
...navigationDarkTheme,
colors: {
...PaperDarkTheme.colors,
...navigationDarkTheme.colors,
headerColor: 'rgb(255, 255, 255)',
bgcolor: "#404040",
surface:"#404040",
btnSearchColor:"#404040",
}
}
const customDefaulttheme = {
...PaperDefaultTheme,
...navigationDefaultTheme,
colors: {
...PaperDefaultTheme.colors,
...navigationDefaultTheme.colors,
headerColor: "white",
bgcolor: "#fafcff",
btnSearchColor:"#006aff",
surface:"white",
}
}
const HomeS = () => {
return <View></View>;
};
const Stack = createStackNavigator();
const App = () => {
const {colors} = useTheme()
const [isDarktheme, setDarkTheme] = useState(false);
const togglemethod = () => {
setDarkTheme(!isDarktheme);
};
return (
<>
<PaperProvider theme={isDarktheme?customDarktheme:customDefaulttheme}>
<NavigationContainer theme={isDarktheme?customDarktheme:customDefaulttheme}>
<StatusBar barStyle="dark-content" />
<Stack.Navigator screenOptions={{headerTitleAlign: 'center', headerStyle: { backgroundColor: colors.headerColor }}}>
<Stack.Screen
name="Home"
component={HomeS}
options={{
headerTitle: (props) => (
<View style={{flexDirection: 'row', width:"300%"}}>
<>
<View>
<Title style={{paddingLeft: 180}}>
<Text>Home</Text>
</Title>
</View>
<View >
<TouchableRipple rippleColor="rgba(0, 0, 0, .32)">
<Switch
value={isDarktheme}
color="yellow"
onValueChange={() => togglemethod()}
style={{
paddingLeft:250,
}}
/>
</TouchableRipple>
</View>
<View style={{}}>
<MaterialCommunityIcons
name={
isDarktheme
? 'moon-waning-crescent'
: 'white-balance-sunny'
}
size={25}
color={isDarktheme ? "yellow" : "blue"}
style={{
paddingLeft: 110,
// paddingBottom: 5,
width: '200%',
flexDirection: 'row',
paddingRight:300
}}
/>
</View>
</>
</View>
),
}}
/>
</Stack.Navigator>
</NavigationContainer>
</PaperProvider>
</>
);
};
export default App;
currently the header looks like this:
look at the distance b/w the switch and Icon. trying to eliminate this was not possible for me. for example the text Home disappears while adjusting other elements like switch or Icon. I know this can be achieved. but I run out of options and glad that someone else can do it and learn from.

Since you want to add the switch and icon on the right, you should use headerRight instead of headerTitle
options={{
headerRight: () => (
<View style={{ flexDirection: 'row', justifyContent: 'flex-end' }}>
// Your switch and icon here
</View>
),
}}

Related

Recat Native / got an invalid value for 'component' prop for the screen

I'm korean. and Im not good at english. please understand about this.
i want if i push the button, move the page.
but
got an invalid value for 'component' prop for the screen
this error keep appear in StyleScreen.
I'm defintly beginner, so if you upload full code, I'm so appreciate that.
this is my App.js code:
import * as React from 'react';
import { useState } from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import MainScreen from './MainScreen';
import DetailScreen from './DetailScreen';
import StyleScreen from './StyleScreen';
const Stack = createStackNavigator();
const App = () => {
const [overlay, setOverlay] = useState(false);
const toggleOverlay = () => {
setOverlay(!overlay);
}
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="MAIN">
<Stack.Screen name="MAIN" component={MainScreen}
options={{
title: '예산'
}}/>
<Stack.Screen name="DETAIL" component={DetailScreen}
options={{
title: '색'
}}/>
<Stack.Screen name="STYLE" component={StyleScreen}
options={{
title: '스타일'
}}/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
this is StyleScreen.js :
import React, { Component } from 'react';
import { useState } from 'react';
import { StatusBar } from 'expo-status-bar';
import { Button, StyleSheet, Text, Dimensions, View, ScrollView, Image, navigation } from 'react-native';
let natural = require('./내추럴.png');
let modern = require('./모던.jpg');
let romantic = require('./로맨틱.jpg');
let NEurope = require('./북유럽.png');
let junk = require('./정크4.jpg');
let minimal = require('./미니멀.jpg');
const HomeScreen=({navigation}) => {
return (
<View style={styles.container}>
<StatusBar style="block"></StatusBar>
<View style={styles.ask1}>
<Text style={styles.askcolor}>선호하는 스타일을</Text>
<Text style={styles.askcolor}>선택해주세요</Text>
</View>
<View style={styles.day2}>
<View style={styles.day}>
<Image style={styles.image} source={modern}/>
<Image style={styles.image2} source={NEurope}/>
</View>
<View style={styles.day}>
<Text style={styles.colorname}> 모던</Text>
<Text style={styles.colorname}> 북유럽</Text>
</View>
<View style={styles.day}>
<Image style={styles.image} source={minimal}/>
<Image style={styles.image2} source={natural}/>
</View>
<View style={styles.day}>
<Text style={styles.colorname}> 미니멀</Text>
<Text style={styles.colorname}> 내추럴</Text>
</View>
<View style={styles.day}>
<Image style={styles.image} source={romantic}/>
<Image style={styles.image2} source={junk}/>
</View>
<View style={styles.day}>
<Text style={styles.colorname}> 로맨틱</Text>
<Text style={styles.colorname}> 정크</Text>
</View>
</View>
<View style={styles.button}>
<Button onPress={() => navigation.navigate('DETAIL')} title='다음으로'/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor:"white"
},
ask1:{
flex:0.3,
justifyContent:"center",
marginTop:70,
marginBottom:40,
},
askcolor:{
fontSize:34,
fontWeight:"900",
paddingHorizontal:30,
},
image:{
height: 130,
width: 158,
borderRadius:10,
backgroundColor:"black"
},
image2:{
height: 130,
width: 158 ,
borderRadius:10,
marginLeft:28,
},
day:{
flexDirection: 'row',
},
day2:{
flex:3,
paddingHorizontal:30,
},
colorname:{
fontSize:17,
fontWeight:"300",
paddingHorizontal:23,
paddingVertical:13,
},
button:{
flex:0.43,
marginLeft:286,
}
})
i think you have not exported your styleScreen component, that might be the issue here and also your "StyleScreen" component is named "HomeScreen" so I would suggest rename is properly and export it by default.
In StyleScreen component, you have imported "navigation" from "react-native" which I think is not correct.
You didn't export StyleScreen component.
Add this at bottom line of your StyleScreen.js.
export default StyleScreen;
try to replace code
const HomeScreen=({navigation}) => {
with
export default StyleScreen =({navigation}) => {

React Native — React-Navigation back button on wrong side of appbar?

Okay so I'm just jumping into React Native and I'm going through the docs with the react-navigation package. Whenever a screen is pushed onto the stack, the animation goes from right-left by default—Also I'm noticing the back button is on the right side of the appbar instead of the left be default. Is this by design or have I set something up incorrectly?
Also ignore the FC I'm using, I know it's not recommended but I'm just getting a feel for RN 😅
See image and code below:
import { StatusBar } from "expo-status-bar";
import { Button, StyleSheet, Text, View } from "react-native";
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import { BaseNavigationContainer } from "#react-navigation/native";
import { FC } from "react";
import { StackScreenProps } from "./Types";
const Home: FC<StackScreenProps> = ({ navigation }) => {
return (
<View style={styles.container}>
<Text>Hello World </Text>
<Button
title="Switch Page"
onPress={() => {
navigation.navigate("About");
}}
/>
</View>
);
};
const About: FC<StackScreenProps> = ({ navigation }) => {
return (
<View style={styles.container}>
<Text>Learn the Process First</Text>
<Button title="Go Back" onPress={() => navigation.goBack()} />
</View>
);
};
const Stack = createNativeStackNavigator();
export default function App() {
return (
<BaseNavigationContainer>
{/* #ts-ignore */}
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="About" component={About} />
</Stack.Navigator>
</BaseNavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});

Navigate to other StackNavigator screen when press button on navbar

I'm pretty new to react and this is my first app.
I have a stack navigator with 2 screens by now: MainMenu and Profile. While the user is in MainMenu, a button on top right corner is shown and I need to redirect the user to the Profile screen when this button is pressed. I need something like this.props.navigation.navigate('Profile') but this does not work, because this, props and navigation are not defined.
My thinks are that I cannot redirect to Profile from this stack navbar, cause Profile is still defined yet, but I don't know another way to do it.
// mainStack.js
import React from 'react';
import { View, Text, TouchableOpacity, Image } from 'react-native';
import { createStackNavigator } from '#react-navigation/stack';
import MainMenu from '../../screens/home/mainMenu';
import Profile from '../../containers/profileContainer';
import Icon from 'react-native-vector-icons/FontAwesome';
import { useSelector } from 'react-redux';
const MainStack = () => {
const Stack = createStackNavigator();
const isAdmin = (useSelector(state => state.auth.user.role) === 'admin');
function renderUserMenu() {
return (
<TouchableOpacity style={{ marginRight: 20 }} onPress={() => console.log("HERE I NEED TO REDIRECT TO THE SCREEN PROFILE") } >
<Icon style={{ color: 'white' }} name='user-circle-o' size={30} />
</TouchableOpacity>
)
}
function LogoTitle() {
return (
<Image
style={{ width: 150, height: 50 }}
source={require('../../assets/logo-with-slogan.png')}
/>
);
}
function renderConfigBtn(_isAdmin) {
if (!_isAdmin) {
return (
<TouchableOpacity style={{ marginRight: 10 }} onPress={() => console.log('Configuraciones')} >
<Icon style={{ color: 'white' }} name='cog' size={30} />
</TouchableOpacity>
)
}
}
return (
<Stack.Navigator>
<Stack.Screen
name="MainMenu"
component={MainMenu}
options={{
headerTitle: props => <LogoTitle {...props} />,
headerRight: () => (
<View style={{ flexDirection: 'row' }}>
{renderConfigBtn(isAdmin)}
{renderUserMenu()}
</View>
),
headerStyle: { backgroundColor: '#0064c8' },
}}
/>
<Stack.Screen
name="Profile"
component={Profile}
options={{
headerStyle: { backgroundColor: '#0064c8' },
}}
/>
</Stack.Navigator>
)
}
export default MainStack;
Also, this stack is inside a navigation container as follows:
import React from 'react';
import { useSelector } from "react-redux";
import { NavigationContainer } from "#react-navigation/native";
import AuthStack from "./authStack";
import MainStack from "./mainStack";
const AppNavigator = props => {
const isAuth = useSelector(state => !!state.auth.access_token);
return (
<NavigationContainer>
{ !isAuth && <AuthStack/>}
{ isAuth && <MainStack/>}
</NavigationContainer>
);
};
export default AppNavigator;
I would appreciate any help.
You can access 'navigation' in options like below
options={({navigation})=>({
headerTitle: props => <LogoTitle {...props} />,
headerRight: () => (
<View style={{ flexDirection: 'row' }}>
{renderConfigBtn(isAdmin,navigation)}
{renderUserMenu(navigation)}
</View>
),
headerStyle: { backgroundColor: '#0064c8' },
})}
Basically you can pass a function as a prop to options and navigation will be passed to it as a parameter.
function renderUserMenu(navigation) {
return (
<TouchableOpacity style={{ marginRight: 20 }} onPress={() => navigation.navigate('YOUR SCREEN') } >
<Icon style={{ color: 'white' }} name='user-circle-o' size={30} />
</TouchableOpacity>
)
}
And you can change the renderUserMenu function like above so that it will do the navigation as required.
Use navigation options and then pass it to the function to navigate to profile:
<Stack.Screen
name="MainMenu"
component={MainMenu}
options={({ navigation }) => ({ ......
We simply can import the useNavigation hook from the react-navigation/native package and can implement navigation with the use of this hook without accessing the navigation props from the component.
For Ex.
First import the hook,
import { useNavigation } from '#react-navigation/native';
Use the hook to implement navigation as below in MainStack.js:
const navigation = useNavigation();
function renderUserMenu() {
return (
<TouchableOpacity style={{ marginRight: 20 }} onPress={() => navigation.navigate("Profile") } >
<Icon style={{ color: 'white' }} name='user-circle-o' size={30} />
</TouchableOpacity>
)
}

Expo Ref usage and Navigation Container Conflicting

I am using Expo Camera to take some user pictures for a profile form. What is happening is when I try to set camera's ref to a state it crashes and throw the following error.
Couldn't find a navigation context. Have you wrapped your app with
'NavigationContainer'? See
https://reactnavigation.org/docs/getting-started for setup
instructions.
Everything is inside a Navigation Container and I really can't figure out what is happening.
Every time I comment ref={(ref) => console.tron.log(ref)} from Expo Camera component everything works fine, but when I uncomment the ref line I get the error.
I am stuck here since last week and nothing on internet about this problem...
Thanks in advance =)
App.js
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { AuthProvider } from './src/context/authContext';
import Routes from './src/routes';
import Theme from './src/theme';
import './src/config/reactotron.config';
export default function App() {
return (
<Theme>
<AuthProvider>
<NavigationContainer>
<Routes />
</NavigationContainer>
</AuthProvider>
</Theme>
);
}
routes.js
import React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import arrowLeft from '../../assets/img/arrow-left-header.png';
import SignUp from '../pages/auth/SignUp';
import Profile from '../pages/auth/Profile';
import Login from '../pages/auth/Login';
import Habits from '../pages/auth/Habits';
import AddChildren from '../pages/auth/AddChildren';
import ChildProfile from '../pages/auth/ChildProfile';
import RegisterFinish from '../pages/auth/RegisterFinish';
import { CameraView } from '../components';
const AuthStack = createStackNavigator();
const theme = {
color: {
brandPrimary: '#16B4A1',
white: '#fff',
},
};
const AuthRoutes = () => {
return (
<AuthStack.Navigator
screenOptions={{
headerTintColor: theme.color.white,
headerStyle: {
backgroundColor: theme.color.brandPrimary,
},
cardStyle: {
backgroundColor: theme.color.white,
},
headerBackTitle: 'Voltar',
}}
>
<AuthStack.Screen
name='Profile'
component={Profile}
options={{
headerLeft: null,
}}
/>
<AuthStack.Screen
name='Login'
component={Login}
options={{ headerShown: false }}
/>
<AuthStack.Screen
name='SignUp'
component={SignUp}
options={{ headerShown: false }}
/>
<AuthStack.Screen
name='RegisterFinish'
component={RegisterFinish}
options={{
headerLeft: null,
headerShown: false,
}}
/>
<AuthStack.Screen
name='TakeAPicture'
component={CameraView}
options={{
headerLeft: null,
headerShown: false,
}}
/>
<AuthStack.Screen name='Habits' component={Habits} />
<AuthStack.Screen name='AddChildren' component={AddChildren} />
<AuthStack.Screen name='ChildProfile' component={ChildProfile} />
</AuthStack.Navigator>
);
};
export default AuthRoutes;
CameraView.js
import React, { useState, useEffect, useRef } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import PropTypes from 'prop-types';
import { Camera } from 'expo-camera';
import { FontAwesome5 } from '#expo/vector-icons';
import { CameraButton, CameraButtonRing } from './styles';
const CameraView = ({ route, navigation }) => {
const cameraRef = useRef()
// CAMERA SETTINGS
const [hasPermission, setHasPermission] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.front);
useEffect(() => {
console.tron.log('rolou')
async function handleCameraPermission() {
const { status } = await Camera.requestPermissionsAsync();
setHasPermission(status === 'granted');
}
handleCameraPermission();
}, []);
const handleTakePictureButton = async () => {
if (!cameraRef) {
console.tron.log('Não tem cam ref')
return
};
let photo = await cameraRef.takePictureAsync();
console.tron.log(photo)
handlePicture(photo)
}
return (
<View style={{ flex: 1 }}>
<Camera
style={{ flex: 1 }}
type={type}
ref={(ref) => console.tron.log(ref)}
>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
border: '1px solid red '
}}
>
<TouchableOpacity
style={{
// flex: ,
// alignSelf: 'flex-end',
// alignItems: 'center',
position: 'absolute',
bottom: 40,
right: 32,
}}
onPress={() => {
setType(
type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back
);
}}
>
<FontAwesome5 name='sync-alt' size={32} color='#fff' />
</TouchableOpacity>
<TouchableOpacity
style={{
// flex: 0.1,
alignSelf: 'flex-end',
height: 56,
width: 56,
backgroundColor: 'transparent',
marginLeft: 'auto',
marginRight: 'auto',
marginBottom: 24,
border: '1px solid red'
}}
onPress={handleTakePictureButton}
>
<View style={{position: 'relative'}}>
<CameraButton />
<CameraButtonRing />
</View>
</TouchableOpacity>
</View>
</Camera>
</View>
);
};
export default CameraView;
For anyone stumbling on this, I really don't know the reason behind, but what was crashing my app with the exact same error, was trying to log to Reactotron. It was the only thing in common with the code on the question, and after removing that, the application stopped crashing and worked just fine.
Now... if anyone discovers the reason, I would really like to know as well.

TypeError: undefined is not an object (evaluating props.navigation.navigate)

I have an icon on the right side of my Header. When pressed I want to be transferred to another page. However, it comes up with an error.
This is my 'icon' screen:
import React, { Component } from 'react';
import { StyleSheet, View, Text, Image, TouchableOpacity } from 'react-native';
const Login = props => {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
onPress={() => {
props.navigation.navigate({routeName: 'Login'});}}>
<Image
source={{
uri:
'https://clipartart.com/images/login-icon-clipart-5.jpg',
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
}
export default Login;
This is my 'navigation' screen:
import {createStackNavigator} from 'react-navigation-stack';
import {createAppContainer} from 'react-navigation';
import React from 'react';
import Homepage from './screens/Homepage';
import Checkoutpage from './screens/Checkoutpage';
import Filterpage from './screens/Filterpage';
import Locationpage from './screens/Locationpage';
import Menupage from './screens/MenuPage';
import Welcomepage from './screens/Welcomepage';
import Loginpage from './screens/Loginpage';
import Finalpage from './screens/Finalpage';
import Login from './Components/Login';
const Navigation = createStackNavigator({
Home:Homepage,
Checkout: Checkoutpage,
Filter: Filterpage,
Location: Locationpage,
Menu: Menupage,
Welcome: Welcomepage,
Login: Loginpage,
Final: Finalpage
},
{
defaultNavigationOptions: {
headerRight:() => <Login/>
}
}
);
I'm very new to react-native. So if you found the problem, can you please explain thoroughly so I understand. Thank you!!
So it looks like you are expecting the navigation object to be part of the props passed to your <Login/> component. This object is only defined for screen components in react-navigate.
This means that you need to get access to the navigation functionality some other way. Luckily, this library provides you with the useNavigation() hook. So using that in your component would look something like:
// react-navigation v5+
import { useNavigation } from '#react-navigation/native';
const Login = () => {
const navigation = useNavigation();
return (
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
onPress={() => {
navigation.navigate({ routeName: "Login" });
}}
>
<Image
source={{
uri: "https://clipartart.com/images/login-icon-clipart-5.jpg",
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
};
It seems to me you are using React Navigation v4.x , in order to use the useNavigation hook you need to upgrade to v5.x.
The navigation prop will be passed to all screens by default and you can use the useNavigation hook like #faelks suggested (if needed in other components).
UPGRADE TO v5 FIRST.
Here you have a little example for v5.x version:
import React from 'react'
import { Button, View, StyleSheet } from 'react-native'
import { NavigationContainer } from '#react-navigation/native'
import { createStackNavigator } from '#react-navigation/stack'
const Home = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go to login" onPress={() => navigation.navigate('Login')} />
</View>
)
const Login = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
)
const Main = createStackNavigator()
const mainConfig = {
// configuration for this stack
initialRouteName: "Home",
}
export default props => (
<NavigationContainer>
<Main.Navigator {...mainConfig}>
<Main.Screen name="Home" component={Home} />
<Main.Screen name="Login" component={Login} />
{/* Other screens for this stack */}
</Main.Navigator>
</NavigationContainer>
)
const styles = StyleSheet.create({
component: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})