Detect active screen in React Native - reactjs

Sorry for my bad English. I have built a navigation bar without using Tab Navigation from React Navigation, everything works fine except when I try to set an 'active' icon, I have handled it with states but the state restarts when I navigate to another window and render the bar again navigation.
I think I have complicated it a bit, but I need to capture the active screen to pass it as status and change the color of the icon to 'active' and the others disabled. I have tried with Detect active screen and onDidFocus but I only received information about the transition, I require the name or id of the screen.
I leave my code (this component is exported to each page where I wish to have the navigation bar). Please, the idea is to not use Tab Navigation from React Native Navigation.
export default class Navbar extends Component {
/** Navigation functions by clicking on the icon (image) */
_onPressHome() {
this.props.navigation.navigate('Main');
}
_onPressSearch() {
this.props.navigation.navigate('Main');
}
render() {
const { height, width } = Dimensions.get('window');
return (
<View style={{ flexDirection: 'row', height: height * .1, justifyContent: 'space-between', padding: height * .02 }}>
/** Icon section go Home screen */
<View style={{ height: height * .06, alignItems: 'center' }}>
<TouchableOpacity
onPress={() => this._onPressHome()}
style={styles.iconStyle}>
<Image
source={HOME_ICON}
style={{ width: height * .04, height: height * .04, }} />
<Text style={[styles.footerText, { color: this.state.colorA }]}>Inicio</Text>
</TouchableOpacity>
</View>
/** Icon section go Search screen */
<View style={{ height: height * .06, alignItems: 'center' }} >
<TouchableOpacity
onPress={() => this._onPressSearch()}
style={styles.iconStyle}>
<Image
source={SEARCH_ICON}
style={{ width: height * .04, height: height * .04, opacity: .6 }} />
<Text style={[styles.footerText, { color: this.state.colorB }]}>Inicio</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
For the navigation I used createStackNavigator and also
const drawerNavigatorConfig = {
contentComponent: props => <CustomDrawerContentComponent {...props}
/>,
};
const AppDrawer = createDrawerNavigator(drawerRouteConfig,
drawerNavigatorConfig);
I do not know if createDrawerNavigator is interfering with something, I read that it generates additional keys. Please help me with this.

import { useIsFocused } from '#react-navigation/native';
function Profile() {
const isFocused = useIsFocused();
return <Text>{isFocused ? 'focused' : 'unfocused'}</Text>;
}
check documentation
https://reactnavigation.org/docs/use-is-focused/

You can use this inViewPort library for checking the view port of the user. This is how you can user the library
render(){
<InViewPort onChange={(isVisible) => this.checkVisible(isVisible)}>
<View style={{flex: 1, height: 200, backgroundColor: 'blue'}}>
<Text style={{color: 'white'}}>View is visible? {this.state.visible </Text>
</View>
</InViewPort>
}

Related

Update Progress bar value when end scrolling in ScrollView on React Native

I have created a functionality , In which show the Progress bar and it's value change according to scrolling the view. the progress bar value should depend that scrolling is end or not if the scrolling is end then the progress bar should completely filled.
I have tired but it's not working. Here my code:
import React, {useState, useEffect} from 'react';
import * as Progress from 'react-native-progress';
import { Card } from 'react-native-paper';
import { Text, View, StyleSheet,ScrollView } from 'react-native';
const scrollView_height = 0;
const scrollViewContent_height = 0;
export default function App() {
const UpdateProgressBar = (progress) => {
setProgress(
Math.abs(
progress.nativeEvent.contentOffset.y /
(scrollViewContent_height - scrollView_height),
),
);
};
return (
<View style={styles.container}>
<Progress.Bar
style={{
position: 'relative',
bottom: 6,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
}}
height={3}
borderWidth={0}
progress={progress_count}
color="red"
width={widthToDp('82%')}
/>
<ScrollView
showsVerticalScrollIndicator={false}
bounces={false}
contentContainerStyle={{paddingBottom: 0}}
onContentSizeChange={(width, height) => {
scrollViewContent_height = height;
}}
onScroll={UpdateProgressBar}
onLayout={(event) =>
(scrollView_height = event.nativeEvent.layout.height)
}
scrollEventThrottle={12}>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Card>
<AssetExample />
</Card>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
}
});
Please Suggest the Solution.
import React, {useState, useEffect} from 'react';
import * as Progress from 'react-native-progress';
import { Card } from 'react-native-paper';
import { Text, View, StyleSheet,ScrollView } from 'react-native';
export default function App() {
const [scrollView_height, setScrollView_height] = useState(0)
const [scrollViewContent_height, setScrollViewContent_height] = useState(0)
const [progress, setProgress] = useState(0)
const UpdateProgressBar = (value) => {
setProgress(
Math.abs(
value.nativeEvent.contentOffset.y /
(scrollViewContent_height - scrollView_height),
),
);
};
return (
<View style={styles.container}>
<Progress.Bar
style={{
position: 'relative',
bottom: 6,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
}}
height={3}
borderWidth={0}
progress={progress}
color="red"
width={widthToDp('82%')}
/>
<ScrollView
showsVerticalScrollIndicator={false}
bounces={false}
contentContainerStyle={{paddingBottom: 0}}
onContentSizeChange={(width, height) => {
setScrollView_height(height);
}}
onScroll={UpdateProgressBar}
onLayout={(event) =>
setScrollView_height(event.nativeEvent.layout.height)
}
scrollEventThrottle={12}>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Card>
<AssetExample />
</Card>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
}
});

How can the image of an ImageBackground be positioned customly

I have a ImageBackground over the whole screen, and I am trying to move the image, which is way bigger, to the left. When I try to position the image using left: -100 this happens (picture below). The ImageBackground is moved, but moves as a whole. What I need is to move only the underlying picture, not the View integrated in the ImageBackground. How can this be achieved?
Styling:
bgImageContainer: {
flex: 1
},
bgImage: {
left: -100
}
Code:
const screenSize = {
width: Dimensions.get('window').width,
height: Dimensions.get('window').height - StatusBar.currentHeight
};
return (
<ImageBackground
source={bgImage}
resizeMode="cover"
style={{ ...screenSize, ...styles.bgImageContainer }}
imageStyle={styles.bgImage}
>
{/* content */}
</ImageBackground>
);
Try this work-around
<View style={{ ...screenSize, ...styles.bgImageContainer }}>
<Image source={bgImage} style={styles.bgImage} resizeMode="cover"/>
{/* content */}
</View>
Styling:
bgImageContainer: {
flex: 1
},
bgImage: {
position:'absolute',
width:SCREEN_WIDTH-100,
height: SCREEN_HEIGHT,
alignSelf:'flex-end' // if this not work make width full and add margin
}
wrap it with SafeAreaView component
import { SafeAreaView } from "react-native";
<SafeAreaView>
<ImageBackground
source={bgImage}
resizeMode="cover"
style={{ flex:1 }}
imageStyle={styles.bgImage}
>
{/* content */}
</ImageBackground>
</SafeAreaView>

How to pass Screen Name to another component

I have a common Header component. How can I pass 'Screen Name' to this component?
I want to pass the 'Screen Name' from Home to HeaderStyle.
I want to use the headerstyle in other component and pass 'Screen Name' to the headerstyle
import HeaderStyle From './HeaderStyle '
export default class Home extends Component {
render (){
return (
// <HeaderStyle>Screen Name</HeaderStyle>
<HeaderStyle Name={"Screen Name"}/>
<HeaderStyle />
)
}
export default class HeaderStyle extends Component {
render() {
return (
<View>
<Header >
<View style={{
width: width, height: hp('12%'),
flexDirection: 'row', backgroundColor: '#141414'
}} >
<Left>
<Image style={styles.logo}
source={require('../assets/images/1x/logo.png')}>
</Image>
</Left>
<View style={{ marginLeft: 280, marginTop: 20 }}>
<Text style={{ color: 'white', fontSize: 35, fontWeight: 'bold' }}>
Should be Dynamic Screen Name</Text></View>
<Right>
<TouchableOpacity onPress={this.ShowHideComponent2}>
<Image style={styles.imgsearch} source={require('../assets/test/a.png')}>
</Image>
</TouchableOpacity>
</Right>
</View>
</Header>
{this.showAssests()}
</View>
);
}
}
Create a function and read window.location.pathname , then in Header component render that function, for Example
export default function currentScreenName(){
let screenName = '';
switch(window.location.pathname){
case '/employees':
screenName = 'Employees';
break;
case '/admin':
screenName = 'Admin';
break;
default:
screenName = 'Dashboard';
}
return screenName;
}
//Header.js
<h1>{currentScreenName()}</h1>
You can simply pass the header prop in static navigationOptions directly inside the screen component.
For example
In your screen component
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
header: <HeaderStyle Name={"Screen Name"}/>
};
/* render function, etc */
}
Inside HeaderStyle component use the props in the Text
<Text style={{ color: 'white', fontSize: 35, fontWeight: 'bold' }}>
{this.props.Name}
</Text>
Find more information on header customisation here
thanks a lot i solve the problem
in the home Screen i send the screen name like this
<Headerstyle title={"text"} />
and in the HeaderStyle i receive the title like this
<Text >{this.props.title}</Text>

Multiple onPress event on a single image component in React Native

I have this picture, and I want to have multiple onPress event for this image.
Example if I touch the head part it will call the function pressHead() and if I touch the chest part it will call the function pressChest().
So far I have tried plotting checkboxes on each part.
import React, { Component } from 'react';
import { View, Image, Alert } from 'react-native';
import { CheckBox } from 'react-native-elements';
export default class Screen extends Component {
pressHead() {
this.setState({checked1: !this.state.checked1})
Alert.alert('Pressed Head', '');
}
pressChest() {
this.setState({checked2: !this.state.checked2})
Alert.alert('Pressed Chest', '');
}
render() {
return (
<View style={{width: 200}}>
<Image
style={{width: 200, resizeMode: 'contain'}}
source={require('../../assets/images/body-diagram.png')}
/>
<CheckBox
containerStyle={{position: 'absolute', top: 22, right: 75, padding: 0}}
checkedIcon='dot-circle-o'
uncheckedIcon='circle-o'
checkedColor='#ff0000'
checked={this.state.checked1}
onPress={() => this.pressHead()}
/>
<CheckBox
containerStyle={{position: 'absolute', top: 70, right: 75, padding: 0}}
checkedIcon='dot-circle-o'
uncheckedIcon='circle-o'
checkedColor='#ff0000'
checked={this.state.checked1}
onPress={() => this.pressChest()}
/>
</View>
);
}
}
This does work. But if I try to use it on a larger device, the position absolute becomes not accurate enough.
Give the constant height for the image and overlay the checkboxes as same above respect to image. Since height is also made constant you don't find any position issues of the checkbox in any screen.
Example :
<View style={{width: 200, height: 600}}>
<Image
style={{width: 200, height: 600 ,resizeMode: 'contain'}}
source={require('../../assets/images/body-diagram.png')}
/>
You can do it by changing your image to <ImageBackground .. /> component after importing it from react-native.
After doing that you can place Touchable things inside of ImageBackground.
Example:
<ImageBackground source={require('../../assets/images/body-diagram.png')} style={{width: 200, height: 600, flexDirection: 'column'}}
<TouchableOpacity onPress={() => alert('first pressed')}>
<Text>First Area</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => alert('second pressed')}>
<Text>Second Area</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => alert('third pressed')}>
<Text>Third Area</Text>
</TouchableOpacity>
<ImageBackground/>

Detect tap on the outside of the View in react native

How to detect tap on the outside of the View(View is a small one width and height are 200). For example, I have a custom View(which is like a modal) and it's visibility is controlled by state. But when clicking outside of it nothing is changed because there is no setState done for that, I need to catch users tap everywhere except inside the modal. How is that possible in React Native?
use a TouchableOpacity around your modal and check it's onPress. Look at this example.
const { opacity, open, scale, children,offset } = this.state;
let containerStyles = [ styles.absolute, styles.container, this.props.containerStyle ];
let backStyle= { flex: 1, opacity, backgroundColor: this.props.overlayBackground };
<View
pointerEvents={open ? 'auto' : 'none'}
style={containerStyles}>
<TouchableOpacity
style={styles.absolute}
disabled={!this.props.closeOnTouchOutside}
onPress={this.close.bind(this)}
activeOpacity={0.75}>
<Animated.View style={backStyle}/>
</TouchableOpacity>
<Animated.View>
{children}
</Animated.View>
</View>
const styles = StyleSheet.create({
absolute: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'transparent'
},
container: {
justifyContent: 'center',
elevation: 10,
}
});
<View
onStartShouldSetResponder={evt => {
evt.persist();
if (this.childrenIds && this.childrenIds.length) {
if (this.childrenIds.includes(evt.target)) {
return;
}
console.log('Tapped outside');
}
}}
>
// popover view - we want the user to be able to tap inside here
<View ref={component => {
this.childrenIds = component._children[0]._children.map(el => el._nativeTag)
}}>
<View>
<Text>Option 1</Text>
<Text>Option 2</Text>
</View>
</View>
// other view - we want the popover to close when this view is tapped
<View>
<Text>
Tapping in this view will trigger the console log, but tapping inside the
view above will not.
</Text>
</View>
</View>
https://www.jaygould.co.uk/2019-05-09-detecting-tap-outside-element-react-native/
I found these solution here, hope it helps
Wrap your view in TouchableOpacity/TouchableHighlight and add onPress Handler so that you can detect the touch outside your view.
Something like :
<TouchableOpacity onPress={() => {console.log('Touch outside view is detected')} }>
<View> Your View Goes Here </View>
</TouchableOpacity>

Resources