Detect tap on the outside of the View in react native - reactjs

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>

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',
}
});

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 active screen in React Native

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>
}

react native search and scroll to hit

I need some help implementing a search and scroll to hit in react native. Did a lot of searches and ended up in some dead ends (found some refs examples I couldn't get to work).
Tried building this snippet as a kick-off:
https://snack.expo.io/#norfeldt/searching-and-scroll-to
import React, { Component } from 'react';
import { Text, View, ScrollView, TextInput, StyleSheet } from 'react-native';
export default class App extends Component {
state = {
text: '41'
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{height: 60, borderColor: 'gray', borderWidth: 1, borderRadius: 10, margin: 5, padding:30, color: 'black', }}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
<ScrollView >
{[...Array(100)].map((_, i) => {return <Text style={styles.paragraph} key={i}>{i}</Text>})}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 10,
backgroundColor: '#ecf0f1',
},
paragraph: {
margin: 10,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
color: '#34495e',
},
});
Any help getting started would be appreciated.
My guess would be:
You could start by binding a ref of your <ScrollView/>.
// ScrollView Ref.
<ScrollView ref={(ref) => this['ScrollView'] = ref}>
...
</ScrollView>
And each of your <Text/> components (by index).
// Text Refs.
<Text ref={(ref) => this[i] = ref} style={styles.paragraph} key={i}>{i}</Text>
You could then set a submit() function.
Said function could find the ref equal to this.state.text using a try catch statement for graceful failure in edge cases.
If found; target x and y offset could be retrieved using measure()
scrollTo() could then be called to scroll to the target component.
// Scroll To Query.
submit = () => {
try {
const { text } = this.state // Text.
const target = this[text] // Target.
// Locate Target.
target.measure((framex, framey, width, height, x, y) => {
// Scroll To Target.
this.ScrollView.scrollTo({x, y, animated: true})
})
} catch (error) {
return console.log(error)
}
}
First of all, I highly recommend you to use FlatList instead of ScrollView. There are a few reasons for this:
FlatList has much more optimized performance in comparison with ScrollView (in scroll view all items are rendered at once, regardless of the fact if they are visible on screen or not)
Moreover, the handling scrolling and rendered items is much simpler in FlatList, you do not need to know anything about x, y axis and pixels, you just work with indexes.
in order to have a comprehensive comparison between these two methods you may look at:
http://matthewsessions.com/2017/05/15/optimizing-list-render-performance.html
Now back to your question, as I said I suggest you to use FlatList, then everything will be as simple as a piece of a cake.
You can find modified example of your expo in:
https://snack.expo.io/HkMZS1SGz
The changes that you need to make in your code, include:
Instead of ScrollView use, FlatList, so change this:
<FlatList
ref={ref => {this.flatListRef = ref;}}
data={new Array(100).fill(0).map((item, index) => index)}
renderItem={({ item }) => (
<Text style={styles.paragraph}>
{item}
</Text>
)}
/>
If you are not already familiar with FlatList, you need to know, the data is added in data prop as an array (I added an array of 100 numbers), and the way it is rendered is given to FlatList as renderItemprop (I added the text with the same styling as you did).
Moreover, note that you do not need to pass ref to <Text>, because FlatList already knows about items that it contains. You just need to add a ref to the FlatList itself:
ref={ref => {this.flatListRef = ref;}}
Now when ever you want to make and scrolling, you can simple call scrollToIndex method of the FlatList, for example write a method called scrollHandler:
// Scroll to Query
scrollHandler = (itemIndex)=>{
this.flatListRef.scrollToIndex({animated: true, index: itemIndex});
}
just pay attention that,flatListRef is the name of the ref assigned to the FlatList.
now, when you want to perform scroll action, you can simply call this method. Forexample, modify your text input to:
<TextInput
style={{height: 60, borderColor: 'gray', borderWidth: 1,
borderRadius: 10, margin: 5, padding:30, color: 'black', }}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
onSubmitEditing={()=>this.scrollHandler(this.state.text)}
/>
Steps
Remember every item's position with onLayout.
scrollTo() position when text input, and only if item found.
Code
const styles = StyleSheet.create({
textinput: {
borderBottomColor: 'purple',
textAlign: 'center',
borderBottomWidth: 2,
height: 40,
marginTop: 20,
},
text: {
textAlign: 'center',
fontSize: 16,
margin: 10,
}
});
export class App extends Component {
data = [];
datapos = {};
scrollref = null;
constructor(props) {
super(props);
/// make 100s example data
for (var i =0; i<100; ++i)
this.data.push(i);
this.state = {
inputvalue: '0'
}
}
render() {
return (
<View style={{flex: 1}}>
<TextInput style={styles.textinput}
value={this.state.inputvalue}
onChangeText={(text) => {
this.setState({inputvalue: text});
let y = this.datapos[+text];
y !== undefined && this.scrollref.scrollTo({ y, animated: true });
}}
/>
<ScrollView
ref={(ref) => this.scrollref = ref}
>
{
this.data.map( (data) => (
<Text style={styles.text}
key={data}
onLayout={(layout) => this.datapos[data] = layout.nativeEvent.layout.y}
>{data}</Text>
))
}
</ScrollView>
</View>
)
}
}
Result:

React-Native Button style not work

Import_this
import {AppRegistry, Text, View, Button, StyleSheet} from 'react-native';
This my React Button code But style not working Hare ...
<Button
onPress={this.onPress.bind(this)}
title={"Go Back"}
style={{color: 'red', marginTop: 10, padding: 10}}
/>
Also I was try by this code
<Button
containerStyle={{padding:10, height:45, overflow:'hidden',
borderRadius:4, backgroundColor: 'white'}}
style={{fontSize: 20, color: 'green'}}
onPress={this.onPress.bind(this)} title={"Go Back"}
> Press me!
</Button>
Update Question:
Also I was try by This way..
<Button
onPress={this.onPress.bind(this)}
title={"Go Back"}
style={styles.buttonStyle}
>ku ka</Button>
Style
const styles = StyleSheet.create({
buttonStyle: {
color: 'red',
marginTop: 20,
padding: 20,
backgroundColor: 'green'
}
});
But No out put:
Screenshot of my phone:-
The React Native Button is very limited in what you can do, see; Button
It does not have a style prop, and you don't set text the "web-way" like <Button>txt</Button> but via the title property <Button title="txt" />
If you want to have more control over the appearance you should use one of the TouchableXXXX' components like TouchableOpacity
They are really easy to use :-)
I had an issue with margin and padding with a Button. I added Button inside a View component and apply your properties to the View.
<View style={{margin:10}}>
<Button
title="Decrypt Data"
color="orange"
accessibilityLabel="Tap to Decrypt Data"
onPress={() => {
Alert.alert('You tapped the Decrypt button!');
}}
/>
</View>
React Native buttons are very limited in the option they provide.You can use TouchableHighlight or TouchableOpacity by styling these element and wrapping your buttons with it like this
<TouchableHighlight
style ={{
height: 40,
width:160,
borderRadius:10,
backgroundColor : "yellow",
marginLeft :50,
marginRight:50,
marginTop :20
}}>
<Button onPress={this._onPressButton}
title="SAVE"
accessibilityLabel="Learn more about this button"
/>
</TouchableHighlight>
You can also use react library for customised button .One nice library is react-native-button (https://www.npmjs.com/package/react-native-button)
If you do not want to create your own button component, a quick and dirty solution is to wrap the button in a view, which allows you to at least apply layout styling.
For example this would create a row of buttons:
<View style={{flexDirection: 'row'}}>
<View style={{flex:1 , marginRight:10}} >
<Button title="Save" onPress={() => {}}></Button>
</View>
<View style={{flex:1}} >
<Button title="Cancel" onPress={() => {}}></Button>
</View>
</View>
Instead of using button . you can use Text in react native and then make in touchable
<TouchableOpacity onPress={this._onPressButton}>
<Text style = {'your custome style'}>
button name
</Text>
</TouchableOpacity >
Style in button will not work, You have to give style to the view.
<View style={styles.styleLoginBtn}>
<Button
color="orange" //button color
onPress={this.onPressButton}
title="Login"
/>
</View>
Give this style to view
const styles = StyleSheet.create({
styleLoginBtn: {
marginTop: 30,
marginLeft: 50,
marginRight: 50,
borderWidth: 2,
borderRadius: 20,
borderColor: "black", //button background/border color
overflow: "hidden",
marginBottom: 10,
},
});
Only learning myself, but wrapping in a View may allow you to add styles around the button.
const Stack = StackNavigator({
Home: {
screen: HomeView,
navigationOptions: {
title: 'Home View'
}
},
CoolView: {
screen: CoolView,
navigationOptions: ({navigation}) => ({
title: 'Cool View',
headerRight: (<View style={{marginRight: 16}}><Button
title="Cool"
onPress={() => alert('cool')}
/></View>
)
})
}
})
Try This one
<TouchableOpacity onPress={() => this._onPressAppoimentButton()} style={styles.Btn}>
<Button title="Order Online" style={styles.Btn} > </Button>
</TouchableOpacity>
You can use Pressable with Text instead of button.
import { StyleSheet, Text, View, Pressable } from 'react-native';
<Pressable style={styles.button} onPress = {() => console.log("button pressed")}>
<Text style={styles.text}>Press me</Text>
</Pressable>
Example Style:
const styles = StyleSheet.create({
button: {
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 12,
paddingHorizontal: 32,
borderRadius: 4,
elevation: 3,
backgroundColor: 'red'
},
text: {
fontSize: 16,
lineHeight: 21,
fontWeight: 'bold',
letterSpacing: 0.25,
color: 'white',
},
});
We can use buttonStyle prop now.
https://react-native-training.github.io/react-native-elements/docs/button.html#buttonstyle
React-native button is very limited, it won't allow styling. use react native elements button or create custom button
button styles does'nt work in react-native, to style your button in react-native easy way is to put it inside the View block like this:
<View
style={styles.buttonStyle}>
<Button
title={"Sign Up"}
color={"#F31801"}/>
</View>
style.buttonStyle be like this:
style.buttonStyle{
marginTop:30,
marginLeft:50,
marginRight:50,
borderWidth:2,
borderRadius:20,
borderColor:'#F31801',
overflow:"hidden",
marginBottom:10,
}
, it will make you able to use designs with buttons
As the answer by #plaul mentions TouchableOpacity, here is an example of how you can use that;
<TouchableOpacity
style={someStyles}
onPress={doSomething}
>
<Text>Press Here</Text>
</TouchableOpacity>
SUGGESTION:
I will recommend using react-native-paper components as they are modified and can be modified much more than react-native components.
To install;
npm install react-native-paper
Then you can simply import them and use.
More details here Here
Wrap the button component inside a view component and change the styles of the view component, it should work. Please refer to the snippet below
<View style={{width: 150, alignSelf: 'center'}}>
<Button onPress={demoFunction} title="clickMe!!" />
</View>
I know this is necro-posting, but I found a real easy way to just add the margin-top and margin-bottom to the button itself without having to build anything else.
When you create the styles, whether inline or by creating an object to pass, you can do this:
var buttonStyle = {
marginTop: "1px",
marginBottom: "1px"
}
It seems that adding the quotes around the value makes it work. I don't know if this is because it's a later version of React versus what was posted two years ago, but I know that it works now.

Resources