React native Hide navigation bar element - javascript

i have code for a working navigation bar, however i need to hide the navigation bar, due to having a video player to when clicked fullscreen mode. the navigation bar does not hide.
Navbar.js file here is the code for the navbar
export default class Navbar extends Component {
render() {
return(
<Header
style={{backgroundColor: Colors.navbarBackgroundColor}}
backgroundColor={Colors.navbarBackgroundColor}
androidStatusBarColor={Colors.statusBarColor}
noShadow={true}
>
{this.props.left ? this.props.left : <Left style={{flex: 1}} />}
<Body style={styles.body}>
<Title style={styles.title}>{this.props.title}</Title>
</Body>
{this.props.right ? this.props.right : <Right style={{flex: 1}} />}
</Header>
);
}
}
Here is the file where I am using the narbar, how can i hide ?
import Navbar from '../component/Navbar';
onFullScreen(fullScreen) {
}
return(
<SideMenuDrawer ref={(ref) => this._sideMenuDrawer = ref}>
//Hide this navbar
<Navbar left={left} right={right} title={this.props.title} />
<Container style={{backgroundColor: '#fdfdfd'}}>
<Video url={'http://techslides.com/demos/sample-videos/small.mp4'}
onFullScreen={status => this.onFullScreen(status)}
style={{ width: Dimensions.get('window').width, height: 200}}/>
</Container>
</SideMenuDrawer>
);
}

using your navbar is not a good idea always it's better to use native element's
but by the way you should have a callback for video play and stop
videoWillPlay = (event) => {
this.setState({flexSize: 0,Height:0});
};
videoWillStop = (event) => {
this.setState({flexSize: 3.5,Height:1});
};
then you can set navbar height zero or if it have flex zero the flex
and you should dynamic style
<Navbar left={left} right={right} title={this.props.title}
style={{flex: this.state.flexSize}}/>
you can also make video play to full size and don't touch navbar

You can conditionally render a component based on a boolean. So you could introduce a boolean you toggle based on if you're in fullscreen or not, then use it to decide if you want to render the nav bar:
{!isFullscreen && <Navbar left={left} right={right} title={this.props.title} />}
In reality that might be this.props.isFullscreen or this.state.isFullscreen depending on where you want to track the value, but that's the general concept.
Here's an example using internal state based on your current code:
export default class YourComponent extends Component {
constructor(props) {
super(props);
this.state = {
isFullScreen: false
};
}
onFullScreen = fullScreen => {
this.setState({
isFullScreen: fullScreen
});
}
render() {
const {isFullScreen} = this.state;
return (
<SideMenuDrawer ref={(ref) => this._sideMenuDrawer = ref}>
{!isFullScreen && <Navbar left={left} right={right} title={this.props.title} />}
<Container style={{ backgroundColor: '#fdfdfd' }}>
<Video
url={'http://techslides.com/demos/sample-videos/small.mp4'}
onFullScreen={this.onFullScreen}
style={{ width: Dimensions.get('window').width, height: 200 }} />
</Container>
</SideMenuDrawer>
);
}
}
I don't have all the info about your project, so this assumes the value passed back to Video's onFullScreen prop is a boolean. If it's an object, you might need to use something like this instead:
onFullScreen = status => {
this.setState({
isFullScreen: status.fullScreen
});
}

Related

React Navigation | How do I change the buttons on a Tab Navigator from a child screen nested in a Stack Navigator?

I have a tab bar that looks like this:
The two side buttons are stack navigators (Learn and Journal) and the middle button needs to navigate the Journal Stack, and depending on what screen in the Journal Stack the user is on, it needs to say and do different things.
const Tab = createBottomTabNavigator();
const TabBarIcon = ({ icon, title, focused }) => {
return (
<View style={styles.iconContainer}>
<FontAwesomeIcon
icon={icon}
color={focused ? Colors.neutral[4] : Colors.neutral[6]}
size={24}
style={styles.icon}
/>
<Text style={[styles.iconText, focused && styles.iconTextFocused]}>
{title}
</Text>
</View>
);
};
const NullScreen = () => null;
const TabNavigator = () => {
return (
<Tab.Navigator
initialRouteName="Journal"
screenOptions={({ route }) => ({
...defaultNavOptions,
headerShown: false,
tabBarStyle: { backgroundColor: Colors.neutral[3] },
tabBarShowLabel: false,
})}
>
<Tab.Screen
name="Learn"
component={LearnStackNavigator}
options={{
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
title={'Learn'}
icon={faUserGraduate}
/>
),
}}
/>
<Tab.Screen
name="Null Screen"
component={NullScreen}
options={{
tabBarButton: ({ focused }) => (
<View
style={{
position: 'relative',
bottom: 25,
width: 80,
height: 80,
borderRadius: '50%',
backgroundColor: 'grey',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
shadowColor: 'black',
shadowOpacity: 0.3,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 3,
}}
>
<TouchableOpacity onPress={() => Alert.alert('hello world')}> // This is the button that I want use for useful things
<View style={[styles.iconContainer, styles.paddingBottom10]}>
<FontAwesomeIcon
icon={faPlus}
color={focused ? Colors.neutral[4] : Colors.neutral[6]}
size={32}
/>
<Text style={styles.iconText}>{'Add Sport'}</Text>
</View>
</TouchableOpacity>
</View>
),
}}
/>
<Tab.Screen
name="Journal"
component={LogbookStackNavigator}
options={{
tabBarIcon: ({ focused }) => (
<TabBarIcon focused={focused} title={'Journal'} icon={faPenAlt} />
),
}}
/>
</Tab.Navigator>
);
};
And here is what the LogbookStackNavigator looks like:
const LogbookStack = createStackNavigator();
const LogbookStackNavigator = () => {
return (
<LogbookStack.Navigator
screenOptions={{
...defaultNavOptions,
headerBackTitleVisible: false,
}}
>
<LogbookStack.Screen
name="Screen1"
component={screen1Component}
options={defaultNavOptions}
/>
<LogbookStack.Screen
name="Screen2"
component={screen2Component}
options={defaultNavOptions}
/>
<LogbookStack.Screen
name="Screen3"
component={screen3Component}
options={entryScreenOptions}
/>
<LogbookStack.Screen
name="Screen4"
component={screen4Component}
options={SaveLogbookScreenOptions}
/>
<LogbookStack.Screen
name="Screen5"
component={screen1Component5}
options={defaultNavOptions}
/>
</LogbookStack.Navigator>
);
};
I know how to use navigation.setOptions, but it only affects the immediate parent navigator, not the grandparent navigator.
Another thing I tried was to make the big circle button on the page itself, but it always rendered underneath the Tab Navigator. If there was a way to make it render above, I think I could just use that. I tried 'position: 'absolute', etc and it always rendered underneath the tab navigator. As it is, I had to basically make a dummy screen in the tab navigator to give me the button on top.
What I need to be able to do, is use big circle button on the Tab Navigator, to navigate to different screens in the LogbookStackNavigator. How do I do that?
Also, I need the title to change from "Add Sport" to "Add " depending on what screen the LogbookStackNavigator is on. How do I do that?
Thanks for your help
Finally figured this out. You have to use react-native-portalize. Just wrap the elements you want to be rendered on top in a
<Portal></Portal>. This will place it above a Bottom Tab navigator.
import { Portal } from 'react-native-portalize';
const FooterButton = () => {
return(
<Portal>
<View>
<Text>I appear above the Tab Navigator!</Text>
</View>
</Portal>
);
export default FooterButton;
Don't forget to wrap the whole app in the the Host:
//In app.js
import { Host } from 'react-native-portalize';
const App = () => {
return (
<Host>
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
</Host>
)
}
export default App;
NOTE: The elements inside the Portal, do not clear when the navigator navigates to another screen. So to get around this, you have to only display the Portal, when the screen is active. Thankfully React Navigation 5+ provides a useIsFocused hook that accomplishes this perfectly.
import { Portal } from 'react-native-portalize';
import { useIsFocused } from '#react-navigation/native';
const FooterButton = () => {
const isFocused = useIsFocused();
// Only display the button when screen is focused. Otherwise, it doesn't go away when you switch screens
return isFocused ? (
<Portal>
<View style={styles.buttonContainer}>
<View style={styles.footer}>{props.children}</View>
</View>
</Portal>
) : null;
};
export default FooterButton;
If you want a modal-style popup, you can wrap react-native-modalize and wrap it with react-native-modalize
Thanks to livin52 on Reddit for the solution

How do I refresh my component when clicked on tab on bottomTabNavigator in React Native, in React Navigation v3?

I am using react-navigation version 3, I have bottom tab navigator, have 4 tabs.
out of which one is chat-screen, called as Chat, containing two views as:
main chat screen for chats or posts
if not login then show with buttons for signup and login.
when clicked on signup or login, it will take to respective screen for signing or logging in.
but from login/signin page when I click on bottom-tab navigator on Chat, it should again reload and check whether user is logged in or not?
problem is when I am navigating to signin/login page, from my tab, then It's not refreshing or called again or remounted.
my chat component is :
class ChatScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
refreshing: false
}
this.onRefresh = this.onRefresh.bind(this);
let WebViewRef;
}
componentDidMount() {
this.didFocusListener = this.props.navigation.addListener(
'didFocus',
() => {
console.log('bottom tab navigator is called');
},
);
if (this.props.userInfo) {
this.get_access_token()
}
else {
console.log("! this.props.userInfo ")
}
}
render() {
if (this.props.userInfo && this.state.access_token)
return (
<SafeAreaView style={{ flex: 1 }}>
<ScrollView
contentContainerStyle={{ flex: 1 }}
refreshControl={<RefreshControl refreshing={this.state.refreshing} onRefresh={this.onRefresh} />}
>
<View style={{ flex: 1 }}>
<WebView
source={{ uri: 'my-demosite-anywebsite.com?access_token=' + this.state.access_token }}
onLoad={() => this.setState({ loading: false })}
ref={WebViewRef => (this.WebViewRef = WebViewRef)}
/>
</View>
</ScrollView>
</SafeAreaView>
)
else if (!this.props.userInfo) {
return <MyCompanyLogoScreen />
}
else {
return <LoadingScreen />
}
}
}
class MyCompanyLogoScreen extends React.Component{
render() {
return (
<View style={styles.container}>
{
!this.state.request_to_login ?
<View> <MyCompanyLogoScreenAllComponents/>
<Button
bgColor="#4cd137"
textColor="#FFFFFF"
secondary
rounded
style={{ alignSelf: 'stretch', marginTop: hp(5),
width: '35%', marginRight: wp(6) }}
caption={'LOGIN UP'}
onPress={() =>
this.navigateToLoginScreen(redirect_to_signup_or_login
= "login")
}
/>
</View>
}
my problem is how can I refresh whole component when I tap on tab at bottomTabNavigator as Chat ?
also didFocus is not working.
React navigation >= 6
React Native Tab Navigation has an option prop as unmountOnBlur. Set it to true and it will reload the tab screens every time you click on tabs.
<Tab.Screen
initialParams={{ ...params, article: null }}
options={{
title: "HomePage",
unmountOnBlur: true,
}}
name="HomePage"
component={ResenhaPage}
/>
you can use higher order component which passes the isFocused prop into a wrapped component. example:
import { withNavigationFocus } from 'react-navigation';
class TabLabel extends React.Component {
componentDidUpdate(prevProps) {
if (prevProps.isFocused !== this.props.isFocused) {
//Call any action to update you view
//fetch data when the component is focused
//To prevent extra component re-renders, you may need to write some logic in shouldComponentUpdate
}
}
render() {
return <Text>{this.props.isFocused ? 'Focused' : 'Not focused'}</Text>;
}
}
// withNavigationFocus returns a component that wraps TabLabel and passes
// in the navigation prop
export default withNavigationFocus(TabLabel);

How to set Icon name on click

In header I add left component - icon, and I want to set icon on click. How can I do that?
I tried to set state value and return component that depends from this value.
<Header
placement="left"
leftComponent={
<Icon
name='keyboard-arrow-left'
color='#ffffff'
size={40}
onPress={}
/>
}
centerComponent={<Text>User Info</Text>}
/>
You can create separate component for icon
export class MyIcon extends Component {
state = { name: 'keyboard-arrow-left' }
render() {
return (
<Icon
name={this.state.name}
color='#ffffff'
size={40}
onPress={() => this.setState({ name: 'close' })}
/>
);
}
}
and use this component for leftComponent of your Header
<Header
placement="left"
leftComponent={
<MyIcon/>
}
centerComponent={<Text>User Info</Text>}
/>
The simplest way to fix this issue is to add a reference to your Icon component. Then use that reference to change any of the props of your icon.
constructor(props){
super(props);
this.state = {};
this.myIcon = '';
}
updateIconName = (nameEntered) => {
this.myIcon.name = nameEntered;
}
render() {
return(
<View style={{flex: 1}}>
<Header
placement="left"
leftComponent={
<Icon
name='keyboard-arrow-left'
color='#ffffff'
size={40}
onPress={this.updateIconName}
ref={(element) => {this.myIcon = element;}}
/>
}
centerComponent={<Text>User Info</Text>}
/>
</View>
);
}

How to open a Component in an onPress call?

So basically I have a Screen in my app that has a Button in it and this button should open a Modal that is also a selfmade component in the same screen js file.
I am setting the state visible in the screen and the button has an onPress handler that toggles the visible state (false/true).
I dont know how to display my own modalComponent when the button is clicked.
btw using react-native-modal
Own modal component:
class PhasenModal extends Component {
render() {
return (
<View>
<Modal isVisible={this.props.visible}>
<View style={{ flex: 1 }}>
<Text>I am a modal</Text>
</View>
</Modal>
</View>
);
}
}
In my ScreenView :
<Button
buttonStyle={styles.phaseButton}
title="Choose"
onPress={() => this.phasenModalHandler()}
/>
The onPress fnct:
phasenModalHandler() {
this.setState({ visible: !this.state.visible });
if (this.state.visible) {
return <PhasenModal visible={this.state.visible} />;
} else {
return;
}
}
I expect the button to show the Modal but it doesnt show anything ,
the state gets toggled correctly tho it switched from false to true.
I guess my onPress fctn is wrong becaus I dont know how to render the component.
Thank you in advance.
What you return from your event handler will not be rendered, so you could instead use the visible value in your state to conditionally render the PhasenModal component.
class ScreenView extends Component {
state = {
visible: false
};
phasenModalHandler = () => {
this.setState(({ visible }) => ({ visible: !visible }));
};
render() {
return (
<>
<Button
buttonStyle={styles.phaseButton}
title="Choose"
onPress={this.phasenModalHandler}
/>
{this.state.visible && <PhasenModal />}
</>
);
}
}
class PhasenModal extends Component {
render() {
return (
<View>
<Modal isVisible>
<View style={{ flex: 1 }}>
<Text>I am a modal</Text>
</View>
</Modal>
</View>
);
}
}

React Conditional Render and Navbar

I am controlling what component should be shown on my applications screen via the state and a switch statement in the main render function. I am writing this in react-native but this is a react structure question.
I also have a Navbar component that I would ideally like to only rerender when the user clicks on a link in the Navbar itself, but I don't know of a great way to do this with how I have the switch statement setup now, it seems like I will have to rerender the Navbar every time depending on what condition is met by the state.
My question is, is there a way that I can still use conditional rendering of components in the render method like I am below AND have a component that is always rendered at the top of the screen like the Navbar? I know this is possible with things like React Router, but is there a better way to structure it without using a tool like React Router or having to rerender the NavBar component every time?
import React from 'react';
import GPS from './GPS/gps';
import Home from './Home';
import Photo from './Camera/Photo';
export default class App extends React.Component {
constructor() {
super();
this.state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
currentView: null,
currentImage: null,
navigation: 'Overview'
};
this.updateNavigation = this.updateNavigation.bind(this);
}
updateNavigation(view) { //Update view function
this.setState({currentView: view});
}
render() {
const { currentView } = this.state;
switch(currentView) {
case null:
return (
<Home updateNav={this.updateNavigation} />
);
break;
case 'GPS':
return (
<View>
<GPS />
<Text onPress={() => this.setState({currentView: null})}>Back</Text>
</View>
);
break;
case 'Camera':
return (
<Photo updateNav={this.updateNavigation} />
);
break;
case 'viewPicture':
return (
<View>
<Image source={{uri: this.state.currentImage.uri}} style={{width: this.state.currentImage.width/10, height: this.state.currentImage.height/12}} />
</View>
);
break;
}
}
}
Always keep render as much as clean.
You can use && operator to do the same instead of using switch case. Use && operator and check every case and render accordingly. Check below code for better understanding.
render() {
const { currentView } = this.state;
return(
{currentView == null && (
<Home updateNav={this.updateNavigation} />
)}
{currentView == "GPS" && (
<View>
<GPS />
<Text onPress={() => this.setState({currentView: null})}>Back</Text>
</View>
)}
{currentView == "Camera" && (
<View>
<Photo updateNav={this.updateNavigation} />
</View>
)}
{currentView == "viewPicture" && (
<View>
<Image source={{uri: this.state.currentImage.uri}} style={{width: this.state.currentImage.width/10, height: this.state.currentImage.height/12}} />
</View>
)}
)
}

Categories