Close modal when clicked outside of <Modal> in react native - react-native

I am making an application in react native. Here I am able to open Modal at a click and also able to close the modal when clicked inside of the Modal. But I also want to close the Modal when clicked outside of it.
Below is my code:
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, Modal, TouchableWithoutFeedback, Alert } from 'react-native';
function Main({ navigation }) {
const [modalVisible, setModalVisible] = useState(false);
return (
{/* This is not working */}
<TouchableWithoutFeedback onPress={() => { setModalVisible(!modalVisible); }}>
<View>
{/* MODAL FOR LANGUAGE */}
<Modal animationType="slide" transparent={true} visible={modalVisible}>
<View>
<Text>Select Language</Text>
</View>
{/* Close modal*/}
<TouchableOpacity onPress={() => { setModalVisible(!modalVisible); }} >
<Text>English</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => { setModalVisible(!modalVisible); }} >
<Text>Hindi</Text>
</TouchableOpacity>
</Modal>
<View>
{/* Open modal*/}
<TouchableOpacity onPress={() => { setModalVisible(true); }} >
<Text>Language</Text>
</TouchableOpacity>
</View>
</TouchableWithoutFeedback>
);
}
I hope from the comments you can see that I am opening modal when clicked on <Text>Language</Text> , and I am able to close modal when clicked on <Text>English</Text> and <Text>Hindi</Text>, which is inside the modal.
To close the modal when clicked on outside of modal I used <TouchableWithoutFeedback onPress={() => { setModalVisible(!modalVisible); }}> , but this is not working.
NOTE: I have intentionally removed all the styling part so that my code here looks clean and that I can make it clear about what I want.

I believe when modal is visible it covers all the screen and you do not have access to the underlaying components. Did you try to create a backdrop inside modal?
Here's an example:
return (
<View>
{/* MODAL FOR LANGUAGE */}
<View>
{/* Open modal*/}
<TouchableOpacity
onPress={() => {
this.setModalVisible(true);
}}
>
<Text>Language</Text>
</TouchableOpacity>
</View>
<Modal animationType="slide" transparent={true} visible={modalVisible}>
<TouchableOpacity
activeOpacity={0.5}
style={{
height: '100%',
backgroundColor: '#e74655',
opacity: 0.5
}}
onPress={() => {
this.setModalVisible(!modalVisible);
}}
/>
<View
style={{
width: '100%',
height: '80%',
borderWidth: 1,
borderColor: '#000',
position: 'absolute',
bottom: 0,
backgroundColor: '#fff'
}}
>
<View>
<Text>Select Language</Text>
</View>
{/* Close modal*/}
<TouchableOpacity
onPress={() => {
this.setModalVisible(!modalVisible);
}}
>
<Text>English</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
this.setModalVisible(!modalVisible);
}}
>
<Text>Hindi</Text>
</TouchableOpacity>
</View>
</Modal>
</View>
)
Which produces this result, where the red area is touchable and closes the modal when you press on it

Related

TouchableOpacity is not working inside ScrollView

I am trying to implement A suggestion box for a text field. While entering input the suggestion box should appear just below to current text field and over the next input filed,
This suggestion should scroll after a maxHeight.
I am have implemented everything just the Touchable is not working inside ScrollView, if I replace ScrollView with simple View Touchable Works but the container will not scroll of course.
How to deal with this?
import React from 'react';
import {
View,
StatusBar,
ScrollView,
TextInput,
Text,
SafeAreaView,
TouchableOpacity,
} from 'react-native';
const TestScreen = () => {
const [val, setVal] = React.useState('');
const [show, setShow] = React.useState(false);
return (
<>
<SafeAreaView style={{flex: 1}}>
<TextInput
placeholder="Text"
value={val}
style={{zIndex: 1}}
onFocus={() => setShow(true)}
onBlur={() => setShow(false)}
onChangeText={t => {
setShow(true);
setVal(t);
}}
/>
<TextInput placeholder="Text" value={val} style={{zIndex: 1}} />
{show && (
<View style={{position: 'absolute', top: 50}}>
<ScrollView
style={{
elevation: 5,
zIndex: 5,
backgroundColor: 'white',
width: 100,
maxHeight: 50,
}}>
<TouchableOpacity onPress={() => setVal('Item1')}>
<Text>Item1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => setVal('Item2')}>
<Text>Item2</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => setVal('Item3')}>
<Text>Item3</Text>
</TouchableOpacity>
</ScrollView>
</View>
)}
</SafeAreaView>
</>
);
};
export default TestScreen;
Please let me know where I am wrong.
So If you are looking for the answer to this problem.
Just remove the onBlur function props from TextField component.
Here you go, you got your own custom textfield suggestion box.
Here the solution code that helped to get this done. I still don't know it is the best idea but It worked for me atleast.
import React from 'react';
import {
View,
StatusBar,
ScrollView,
TextInput,
Text,
SafeAreaView,
TouchableOpacity,
} from 'react-native';
import {Button} from 'native-base';
const TestScreen = () => {
const [val, setVal] = React.useState('');
const [show, setShow] = React.useState(false);
return (
<>
<SafeAreaView style={{flex: 1}}>
<TouchableOpacity
style={{flex: 1}}
activeOpacity={1}
onPress={() => {
if (show) {
setShow(false);
}
}}>
<TextInput
placeholder="Text"
value={val}
style={{zIndex: 1}}
onFocus={() => setShow(true)}
onChangeText={t => {
setShow(true);
setVal(t);
}}
/>
<TextInput placeholder="Text" value={val} style={{zIndex: 1}} />
{show && (
<View
style={{
position: 'absolute',
top: 50,
}}>
<ScrollView
style={{
elevation: 5,
zIndex: 5,
backgroundColor: 'white',
width: 100,
maxHeight: 50,
}}>
<TouchableOpacity
onPress={() => {
setShow(false);
setVal('Item1');
}}>
<Text>Item1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => setVal('Item2')}>
<Text>Item2</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => setVal('Item3')}>
<Text>Item3</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => setVal('Item4')}>
<Text>Item4</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => setVal('Item5')}>
<Text>Item5</Text>
</TouchableOpacity>
</ScrollView>
</View>
)}
</TouchableOpacity>
</SafeAreaView>
</>
);
};
export default TestScreen;

react native: modal is not displaying

I am new to react-native and I am trying to display modal in react-native with following code
<View>
<View onPress={() => {this.toggleModal(true) }} onBackdropPress={ () =>
{this.hideModal(false)}}>
<View>
<OcticonsIcons name='plus' size={19}/>
<Text>QUICK ACTION</Text>
</View>
<View>
<View>
<Image source={require('../images/truck.png')}
/>
<Image source={require('../images/taxi(1).png')}
/>
<Image source={require('../images/tour.png')}
/>
</View>
</View>
</View>
</View>
<Modal visible={this.state.isModalVisible} animationType = "slide" transparent =
{false}>
<View style={{ flex: 1 }}>
<Text style={{ fontWeight:'bold', fontSize: 20, color: '#f79334', marginTop: 15
}} > Services </Text>
</View>
</Modal>
toggleModal(visible){
this.setState({ isModalVisible: visible });
}
hideModal(visible){
this.setState({ isModalVisible: visible })
}
but it's not working, can anyone tell me what wrong with my code, thank you.
The thing is you cant have onPress function on components, its solely for just showing. To use onPress you have to use TouchableOpacity.
Check the code below :
<View>
<TouchableOpacity onPress={() => {this.toggleModal(true) }} onBackdropPress={ () =>
{this.hideModal(false)}}>
<View>
<OcticonsIcons name='plus' size={19}/>
<Text>QUICK ACTION</Text>
</View>
<View>
<View>
<Image source={require('../images/truck.png')}
/>
<Image source={require('../images/taxi(1).png')}
/>
<Image source={require('../images/tour.png')}
/>
</View>
</View>
</TouchableOpacity>
</View>
<Modal visible={this.state.isModalVisible} animationType = "slide" transparent =
{false}>
<View style={{ flex: 1 }}>
<Text style={{ fontWeight:'bold', fontSize: 20, color: '#f79334', marginTop: 15
}} > Services </Text>
</View>
</Modal>
toggleModal = (visible) =>{
this.setState({ isModalVisible: visible });
}
hideModal = (visible) => {
this.setState({ isModalVisible: visible })
}
Hope it helps. feel free for doubts

React-Native modal does not open

I am trying to open the modal through a TouchableOpacity (the second line). I got it to work on a clean application, but when I basically copy and paste to a my current application it does not open at all... Another important point is that this is a card component that is within react-native-deck-swiper. That is my guess for why is won't work.
Top part of my code:
constructor() {
super();
this.state = {
modalVisible: false
}
}
setModalVisible = (visible) => {
this.setState({modalVisible: visible})
}
Bottom Part of my code with the modal
<View style={{flex: 1, justifyContent: 'flex-end', paddingLeft: 5, paddingTop: 10}}>
<TouchableOpacity onPress={() => { this.setModalVisible(true)}}>
<Icon name="more" style={{fontSize: 40}} />
</TouchableOpacity>
</View>
</View>
</View>
</View>
<View style={{padding: 5}}>
<Text style={{fontSize: 20}}>10 miles away</Text>
</View>
<View style={{marginTop: 22, flex:1}}>
<Modal
animationType="slide"
transparent={true}
visible={this.state.modalVisible}
onRequestClose={() => {
alert('Modal has been closed.');
}}>
<View style={{marginTop: 22}}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
</View>
You need to bind you function in the constructor or use arrow functions or else this wont be pointing to your component:
setModalVisible = (visible) => {
this.setState({modalVisible: visible})
}
According to your code, don't use the Arrow function. if you want arrow function then bind it, otherwise use below function.
setModalVisible(visible) {
this.setState({modalVisible: visible});
}

react-native-swipeout onPress method disables containing component's onPress method

I have the following flatlist render method that upon tapping on a list item, it will call the this._onPress method:
render() {
return (
<TouchableOpacity onPress={this._onPress} >
<View style={styles.bookItem} >
<Image style={styles.cover} source={{uri:this.props.coverURL}}/>
<View style={styles.info} >
<Text style={styles.title}>{this.props.title} </Text>
<Text style={styles.author}>{this.props.author}</Text>
<Text style={{height: 8}}/>
</View>
<View style={styles.rightIcon}>
<Icon name="chevron-right" size={28} color={'#AAAAAA'} />
</View>
</View>
</TouchableOpacity>
);
}
After I added the swipeout tag in the following code, the swipeout works but tapping on an item no longer calls the this._onPress method:
render() {
// Buttons
var swipeoutBtns = [
{
text: 'Delete',
onPress: this._buttonPress
}
]
return (
<TouchableOpacity onPress={this._onPress} >
<Swipeout right={swipeoutBtns} >
<View style={styles.bookItem} >
<Image style={styles.cover} source={{uri:this.props.coverURL}}/>
<View style={styles.info} >
<Text style={styles.title}>{this.props.title} </Text>
<Text style={styles.author}>{this.props.author}</Text>
<Text style={{height: 8}}/>
</View>
<View style={styles.rightIcon}>
<Icon name="chevron-right" size={28} color={'#AAAAAA'} />
</View>
</View>
</Swipeout>
</TouchableOpacity>
);
}
Is this a restriction of react-native-swipeout?
If you were to have Swipeout as the first tag and touchable as the next nested tag I think it would work. However, its seems to make the Swipeout functionality less responsive

How to hide Modal by clicking out of modal body in React Native [duplicate]

This question already has answers here:
Close react native modal by clicking on overlay?
(24 answers)
Closed last month.
I have written a code to hide modal whenever user click to the 'hide me' text which is in the modal but I also want modal to hide when we click outside the modal. I can use 'TouchableWithoutFeedback' but it doesn't work for me. How can I use 'TouchableWithoutFeedback' or any other solution for this?
this.state = {
showPopupModal: false
}
hideModal(){
this.setState({showPopupModal: false});
}
showModal(){
this.setState({showPopupModal: true});
}
return(
<Conatiner>
<View>
<TouchableOpacity onPress={() => { showModal(); }}>
<Text> open modal <Text>
</TouchableOpacity>
</View>
<Modal visible={this.state.showPopupModal}>
<View>
<TouchableOpacity onPress={() => { hideModal(); }}>
<Text> hide me </Text>
</TouchableOpacity>
</View>
</Modal>
</Container>
);
You have to set isVisible and onBackdropPress attributes of Modal,eg:
<Modal isVisible={this.state.showPopupModal} onBackdropPress={() => this.hideModal()} >
..
</Modal>
You have not assigned props to the Modal, doing
<Modal visible={this.state.showPopupModal}>
<View>
<TouchableOpacity onPress={() => { hideModal(); }}>
<Text> hide me </Text>
</TouchableOpacity>
</View>
</Modal>
Should solve this.
This is the only way I could do this without installing any additional libraries!
<Modal
visible={this.state.modal}
animationType="fade"
transparent={true}
onRequestClose={this.handleClose}>
<Pressable
onPress={() => {
this.handleClose();
}}
style={[
Platform.OS === 'ios' ? styles.iOSBackdrop : styles.androidBackdrop,
styles.backdrop,
]}
/>
...
</Modal>;
Add this below styles in to your styles.
const styles = StyleSheet.create({
iOSBackdrop: {
backgroundColor: '#000000',
opacity: 0.3,
},
androidBackdrop: {
backgroundColor: '#232f34',
opacity: 0.32,
},
backdrop: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
},
});
this.state = {
showPopupModal: false
}
hideModal(){
this.setState({showPopupModal: false});
}
showModal(){
this.setState({showPopupModal: true});
}
return(
<Conatiner>
<View>
<TouchableOpacity onPress={() => { showModal(); }}>
<Text> open modal <Text>
</TouchableOpacity>
</View>
<TouchableWithoutFeedback onPress={() => { hideModal(); }}>
<Modal visible={this.state.showPopupModal}>
<TouchableWithoutFeedback onPress={() => { hideModal(); }}>
<View>
<TouchableOpacity onPress={() => { hideModal(); }}>
<Text> hide me </Text>
</TouchableOpacity>
</View>
</TouchableWithoutFeedback>
</Modal>
</TouchableWithoutFeedback>
</Container>
);
this solution is working for me.