I am trying to show a modal without going to another screen, I want it to be displayed on the current screen but not through navigation. The modal doesn't pop up and I don't know the problem.
I am using the renderModal to show the modal on the screen.When I use this.props.navigation.navigate('AnotherModal'), it works but goes to another screen,this time I want to show modal on the same screen.
import * as React from 'react';
import { Text, View, Image,
StyleSheet,Alert,Modal,TouchableHighlight } from 'react-native';
import { Constants } from 'expo';
import { Appbar, Colors, FAB } from 'react-native-paper';
import ProductsModal from './ProductsModal';
import ModalTester from './ModalTester';
export default class AppBar extends React.Component {
state = {
modalVisible: false,
};
setModalVisible(visible)
{
this.setState({modalVisible: visible});
}
renderModal() {
return (
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.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>
);
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.appbar}>
<Appbar style={styles.piece}>
<Appbar.Action
icon={require('../../assets/devices.png')}
onPress={this.renderModal.bind(this)}
/>
</Appbar>
<View>
<Image
source={require('../../assets/cutout.png')}
style={styles.cutout}
pointerEvents="none"
/>
<FAB
icon={require('../../assets/add_circle.png')}
color="#b2beb5"
onPress={() => navigate('Homes')}
style={styles.fab} />
</View>
<Appbar style={[styles.piece, styles.right]}>
<Appbar.Action
icon={require('../../assets/account_box.png')}
onPress={() => console.log('Account pressed')}
/>
</Appbar>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
//backgroundColor: '#ecf0f1',
padding: 8,
},
appbar: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
height: 56,
flexDirection: 'row',
},
piece: {
flex: 1,
backgroundColor: Colors.grey300,
},
right: {
justifyContent: 'flex-end',
},
cutout: {
height: 56,
width: 80,
tintColor: Colors.grey300,
},
fab: {
position: 'absolute',
margin: 12,
bottom: 16
}
});
You should try to bind your setModalVisible in the constructor first:
constructor(props) {
super(props);
this. setModalVisible = this. setModalVisible.bind(this);
}
And then change your first Appbar.Action to something like this:
<Appbar.Action
icon={require('../../assets/devices.png')}
onPress={() => this. setModalVisible(true)}
/>
Also you have to add your Modal to the rendered code
...
<Appbar.Action
icon={require('../../assets/account_box.png')}
onPress={() => console.log('Account pressed')}
/>
</Appbar>
{this.renderModal()}
</View>
I'm not sure the bind is necessary though
Since screen does not change, your Modal needs to be within the render method of that screen. This means it can be handled by the state of the component. For example to show it you can:
<Appbar.Action
icon={require('../../assets/devices.png')}
onPress={() => this.setModalVisible(true)}
/>
In the main render you can just add directly your renderModal, 'cause its visible prop is sufficient to handle the behavior:
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.appbar}>
<Appbar style={styles.piece}>
<Appbar.Action
icon={require('../../assets/devices.png')}
onPress={this.renderModal.bind(this)}
/>
</Appbar>
<View>
{this.renderModal()}
<Image
source={require('../../assets/cutout.png')}
style={styles.cutout}
pointerEvents="none"
/>
<FAB
icon={require('../../assets/add_circle.png')}
color="#b2beb5"
onPress={() => navigate('Homes')}
style={styles.fab} />
</View>
<Appbar style={[styles.piece, styles.right]}>
<Appbar.Action
icon={require('../../assets/account_box.png')}
onPress={() => console.log('Account pressed')}
/>
</Appbar>
</View>
);
}
Related
I have been simply trying to render a card from react-native-elements UI library. Here is the documentation that I've been looking through and literally copied and pasted from: https://reactnativeelements.com/docs/1.2.0/card
Here is my Deal component:
import { View } from 'react-native'
import { Card, ListItem } from 'react-native-elements'
const Deal = () => {
const users = [
{
name: 'brynn',
avatar: 'https://www.w3schools.com/howto/img_avatar2.png',
},
]
return (
<View>
<Card containerStyle={{ padding: 0 }}>
{users.map((u, i) => {
return (
<ListItem
key={i}
roundAvatar
title={u.name}
leftAvatar={{ source: { uri: u.avatar } }}
/>
)
})}
</Card>
</View>
)
}
export default Deal
Here is my SecondScreen component in which I am trying to render Deal:
import { StyleSheet, Text, View } from 'react-native'
import Step from '../components/Step'
import MyCarousel from '../components/MyCarousel'
import Ratings from '../components/Ratings'
import Deal from '../components/Deal'
export default function SecondScreen({ route, navigation }) {
const { image } = route.params
return (
<>
<View>
<Text
style={{ fontSize: '16px', marginLeft: 10, marginTop: 15 }}
>
Daily Deals
</Text>
<View
style={{
borderBottomColor: 'black',
borderBottomWidth: StyleSheet.hairlineWidth,
}}
/>
<View style={{ marginTop: 10 }}>
<Deal />
</View>
</View>
</>
)
}
Here is what it renders at the end:
Any help would be appreciated!
Edit: I have decided to use another component in the meantime. This seems like possibly deprecated component or something.
Try adding flex or height for <View />
<View style={{ flex: 1, marginTop: 10 }}>
<Deal />
</View>
Inside your Deal component, you have a <View /> wrapper around the <Card /> component. The one inside Deal file, NOT the one wrapping it in SecondScreen file.
Have you tried removing that excess <View />?
If you want to keep that <View />, have you tried giving that specific <View /> a style={{ height: 100px }} or style={{ flex: 1 }} property?
hello I'm developing a react native app everything is fine but I have a problem
return (
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
<StatusBar
translucent={true}
backgroundColor={'rgba(0, 0, 0, 0.3)'}
barStyle={'light-content'}
/>
{ this.gradient }
<ScrollView
style={styles.scrollview}
scrollEventThrottle={200}
directionalLockEnabled={true}
>
{ carousel }
<FlatList
data={ this.state.GridListItems }
renderItem={ ({item}) =>
<TouchableOpacity
style={styles.GridViewContainer}
onPress={() => this.props.navigation.push('ProfileScreen', { height: "6'2", category: item.key })}>
<ImageBackground
source={{ uri: item.img }}
style={{width: '108%', height: '110%', justifyContent:'center'}}
>
<Text style={styles.GridViewTextLayout} > {item.key} </Text>
</ImageBackground>
</TouchableOpacity>
}
numColumns={2}
/>
</ScrollView>
</View>
</SafeAreaView>
);
styles
safeArea: {
flex: 1,
backgroundColor: colors.black
},
container: {
flex: 1,
backgroundColor: colors.background1
},
when I scroll down you see the mobile battery and wifi (top bar) is in the app
I want the app to be below the mobile topbar how can I achieve that?
here is an expo qr code
once try this and let me know your results:
import React,{Fragment} from 'react';
return (
<Fragment>
<SafeAreaView style={{ flex: 0, backgroundColor: 'red' }} />
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
{ this.gradient }
<ScrollView
style={styles.scrollview}
scrollEventThrottle={200}
directionalLockEnabled={true}
>
{ carousel }
<FlatList
data={ this.state.GridListItems }
renderItem={ ({item}) =>
<TouchableOpacity
style={styles.GridViewContainer}
onPress={() => this.props.navigation.push('ProfileScreen', { height: "6'2", category: item.key })}>
<ImageBackground
source={{ uri: item.img }}
style={{width: '108%', height: '110%', justifyContent:'center'}}
>
<Text style={styles.GridViewTextLayout} > {item.key} </Text>
</ImageBackground>
</TouchableOpacity>
}
numColumns={2}
/>
</ScrollView>
</View>
</SafeAreaView>
);
i added safeareaview (flex:0) for statusBar you can apply any color you want.
provide options in your navigator file as:
navigationName: {
screen: fileName,
navigationOptions: ({ navigation }) => {
if (Platform.OS === "android") {
return {
title: 'images',
headerStyle: {
backgroundColor: '#382464',
height: 50,
},
headerTitleStyle: {
color: '#fff',
},
headerTintColor: '#fff',
// header: props => <UriBar {...props} />
}
} else {
return {
header: null
}
}
}
},
you can also use statusBar for android
You should use SafeAreaView.
It will render your component without overlapping the "top bar".
import { SafeAreaView } from 'react-native'
...
return (
<SafeAreaView>
// your components
<SafeAreaView/>
)
Edit:
As you can see in the docs.
Simply wrap your top level view with a SafeAreaView with a flex: 1 style applied to it. You may also want to use a background color that matches your application's design.
So if you already using SafeAreaView, maybe you don't have flex: 1 and it's not working in the way you want.
am new to react native and i have 2 js file(Component). 1 of the file is the modal jsx and i want to open this modal from other js file.
Modal JS file
import React, {Component} from 'react';
import { Platform, Text,View, StyleSheet, TouchableOpacity} from 'react-native';
import Modal from 'react-native-modal';
import { Icon,
Picker,
Form,
Item,
Button,
Input} from 'native-base';
export default class MyPopup extends Component{
state = {
isModalVisible: this.props.isModalVisible
};
constructor(){
super();
}
render() {
return (
<View style={styles.container}>
<Modal isModalVisible={true}>
onRequestClose={() => this.closeModal()}>
<View style={styles.headerContent}>
<View style={styles.headerItems}>
<Icon name='md-grid' />
<Text style={styles.headerText}>Version Mail</Text>
</View>
</View>
<View style={styles.modalContainer}>
<View style={styles.titleRow}>
<View style={styles.titleText}>
<Text>Book:</Text>
<Text> MAIN Reader</Text>
</View>
<View style={styles.titleTableText}>
<Text>Version:</Text>
<Text> T12345 User</Text>
</View>
</View>
<View style={styles.lineDiv}/>
<View style={styles.titleText}>
<View style={styles.itemMarginAlone}>
<Text>Server</Text>
<View style={{flexDirection:'row'}}>
<Icon active name='person'/>
<Picker mode="dropdown" style={{width:350}}>
<Item label="User_1" value="key0" />
<Item label="User_2" value="key1" />
<Item label="User_3" value="key2" />
<Item label="User_4" value="key3" />
<Item label="User_5" value="key4" />
</Picker>
</View>
</View>
<View>
<Text>Notes</Text>
<Item style={{width:350}}>
<Icon active name='clipboard' />
<Input placeholder='Notes...'/>
</Item>
</View>
</View>
<View style={styles.titleText}>
<View style={styles.itemMarginAlone}>
<Text>Guests</Text>
<View style={styles.titleText}>
<Button bordered style={styles.btnGuest}>
<Text>1</Text>
</Button>
<Button bordered style={styles.btnGuest}>
<Text>2</Text>
</Button>
<Button bordered style={styles.btnGuest}>
<Text>3</Text>
</Button>
<Button bordered style={styles.btnGuest}>
<Text>4</Text>
</Button>
<Button bordered style={styles.btnGuest}>
<Text>5</Text>
</Button>
<Button bordered style={styles.btnGuest}>
<Text>6</Text>
</Button>
<Button bordered style={styles.btnGuest}>
<Text>7</Text>
</Button>
<Button bordered style={styles.btnGuest}>
<Text>8</Text>
</Button>
<Button bordered style={styles.btnGuest}>
<Text>+</Text>
</Button>
</View>
</View>
</View>
<View style={styles.lineDiv}/>
<View style={styles.btnAction}>
<Button warning style={styles.btnAlign}><Text style={styles.btnAlign}> Submit</Text>
<Icon active name='keypad' /></Button>
<Button warning style={styles.btnAlign}><Text style={styles.btnAlign}> Close</Text>
<Icon active name='keypad' /></Button>
</View>
</View>
</Modal>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'green',
},
modalContainer: {
backgroundColor: 'white',
},
innerContainer: {
alignItems: 'flex-end',
},
headerContent:{
height: 55,
backgroundColor: '#f7b50c',
},
txtFont:{
fontSize:12,
},
headerItems:{
margin:10,
flex: 1,
flexDirection:'row',
},
headerText:{
margin : 5,
fontSize:18,
},
titleRow:{
margin :8,
flexDirection : 'row',
justifyContent: 'space-between',
},
titleText:{
margin :8,
flexDirection : 'row',
},
titleTableText:{
margin :8,
flexDirection : 'row',
},
lineDiv:{
borderBottomColor: 'grey',
borderBottomWidth: 1.5,
margin: 10,
},
itemMarginAlone:{
margin:10,
},
btnAlign:{
margin:15,
},
btnGuest:{
width: 55,
margin:8,
justifyContent:'center',
},
btnAction:{
flexDirection: 'row',
justifyContent: 'flex-end',
}
});
Calling Js file
HOME JS file
How will i call this popup after importing. My popup is component and i need to revoke that when button clicked from first my home js
Thanks in advance
Your MyPopup is taking this.props.isModalVisible to judge visibility of the component. You can use that property to decide the visibility.
Sample
export default class MyPopup extends React.Component {
...
render() {
const { isModalVisible } = this.props;
return (
isModalVisible &&
<View style={styles.container}>
...
</View>
);
}
}
To use it
...
import MyPopup from '...'
...
class Home extends React.Component {
...
render() {
return(
...
<MyPopup isModalVisible={MODAL_VISIBILITY_PREDICATE} />
...
)
}
}
Hope this will help!
I also needed this kind of Modal. By using you code and research i tried to create reusable Model.
Please comment below for any suggestions.
export default class ImageModel extends Component {
constructor(props) {
super(props);
}
render() {
const visbility=this.props;
return (
<Modal animationType={"slide"} transparent={false}
visible={this.props.visbility}
onRequestClose={() => { console.log("Modal has been closed.") }}>
<View style={styles.modal}>
<Image
style={{ width: '100%', height: 200, resizeMode: 'stretch' }}
source={{ uri: 'https://4.bp.blogspot.com/-krdeTqQLML8/Wyf2oV7eedI/AAAAAAAABpI/OZ759swV7L8wWtt2pwBXIgp6aPz33r01gCLcBGAs/s400/fist%2Bapp.jpg' }}
/>
<Text style={styles.text}> Javascript Tutorial With Example</Text>
<TouchableHighlight style={styles.touchableButton}
onPress={() => { this.props.viewImageModel() }}>
<Text style={styles.text}>Close Modal</Text>
</TouchableHighlight>
</View>
</Modal>
)
}
}
const styles = StyleSheet.create(
{
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
margin: 20
},
modal: {
flex: 1,
alignItems: 'center',
backgroundColor: '#2196f3',
justifyContent: 'center',
padding : 10,
},
text: {
color: '#fff',
fontSize: 20,
textAlign: 'center',
},
touchableButton: {
width: '70%',
padding: 10,
backgroundColor: '#f06292',
marginBottom: 10,
marginTop: 30,
},
});
Above Model called from below Child component
export default class AddExpense extends React.Component {
constructor(props){
super(props);
this.state={
reciptVisible:false
}
this.viewImageModel= this.viewImageModel.bind(this);
}
viewImageModel(){
if(this.state.reciptVisible == true)
this.setState({reciptVisible:false})
else
this.setState({reciptVisible:true})
}
render(){
return (
// Your Code
{this.state.reciptVisible && (
<ImageModel visbility={this.state.reciptVisible} viewImageModel={this.viewImageModel}></ImageModel>
)}
<TouchableOpacity onPress={ this.viewImageModel } >
<Image
source={{
uri: 'data:image/jpeg;base64,' + this.state.filePath.data,
}}
style={{ width: 100, height: 80 }}
/>
</TouchableOpacity>
)}
}
Anyone has experience of implementing react-native-modal?
While I'm using it, modal isn't closed when I tap outside of modal.
Here is what I've tried
Adding onBackdropPress(() => {this.props.hideModal()})
Adding TouchableWithoutFeedback inside and outside of components
and many other approaches...
Here is my the screen where I want to show my modal.
render() {
return (
<View style={{flex: 1}}>
<ScrollView>
// CONTENT HERE
{this._renderModal()} //rendering modal here
<FABs onFABsPress={this._showModal} /> // I open Modal when I press the FABs button
</ScrollView>
</View>
)
);
_renderModal = () => {
return (
<CameraImageSelectModal
hideModal={this._hideModal}
isModalVisible={this.state.isModalVisible}
navigation={this.props.navigation}
/>
)
}
Here is modal component : CameraImageSelectModal.js
render() {
let { isModalVisible } = this.props;
return (
<View>
<Modal
isVisible={isModalVisible}
onBackdropPress={() => {console.log('hey')}}>
transparent={true}>
<View style={styles.modalContainer}>
<View style={styles.modalTitleTextContainer}>
<Text style={styles.modalTitleText}>Hello World</Text>
</View>
<View style={styles.modalContentTextContainer}>
<Text style={styles.modalContentText}></Text>
</View>
<View style={styles.modalButtonContainer}>
<Button transparent onPress={this._handleCameraPress}>
<Text style={[styles.modalText, styles.black]}>Camera</Text>
</Button>
<Button transparent onPress={this._handleAlbumPress}>
<Text style={styles.modalText}>Album</Text>
</Button>
</View>
</View>
</Modal>
</View>
Thanks!!
I don't think the modal has that built in functionality, but you could create your own component that does. Here is a quick implementation. You might have to mess around with padding and margin to get it how you like, but this will allow the modal to be dismissed when pressing outside.
import React, { Component } from "react"
import { Modal, StyleSheet, View, TouchableHighlight } from "react-native"
const styles = StyleSheet.create({
container: {
zIndex: 1,
margin: 25,
backgroundColor: "white"
},
background: {
flex: 1
},
outerContainer: {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: "center"
}
})
const MyModal = props => (
<Modal transparent={true} animationType={"slide"} visible={props.visible} onRequestClose={() => props.onRequestClose()}>
<TouchableHighlight style={styles.background} onPress={() => props.onRequestClose()} underlayColor={"transparent"}>
<View />
</TouchableHighlight>
<View style={ styles.outerContainer }>
<View style={styles.container}>
{props.children}
</View>
</View>
</Modal>
)
export { MyModal }
I just figured out why onBackdropPress = {() => console.log("Pressed")} didn't work..!!! onBackdropPress property was added since its version 3.xx and I was using 2.5.0 version.
So yarn update react-native-modal solved the issue.
If anyone encounters the problem that the library/component doesn't work as expected as you seen on documentation, try to check your package version number!
Cheers!
<Modal
isVisible={isModalVisible}
customBackdrop={
<View
style={styles.backDropContainer}
onTouchEnd={() => setModalVisible(false)}
/>
}
onBackdropPress={() => setModalVisible(false)}>
<View style={styles.modalContainer}>
<FlatList data={DATA} renderItem={() => <Text>hehehe</Text>} />
</View>
</Modal>
Style:
const styles = StyleSheet.create({
backDropContainer: {
flex: 1,
backgroundColor: 'black',
opacity: 0.5,
},
modalContainer: {
flex: 0.5,
backgroundColor: 'white',
padding: 10,
borderRadius: 10,
},
});
I am trying to have my Animated View come downward and over the content of the ScrollView instead of over my top fixed position bar, but when the Animation begins the animated view ends up eating the space of the container bar. I have played with paddingTop, marginTop, but seems to be a hack.
Here is a self contained code sample that shows what I'm trying to do:
import React, { Component } from 'react';
import {
AppRegistry, StyleSheet, Text, View, Animated, Dimensions, ScrollView,
Button
} from 'react-native';
const { width } = Dimensions.get('window');
const make_text = (text='Hello', color='blue') => (
<Text
style={{textAlign: 'center', fontSize: 24, backgroundColor: color, margin: 20}}>
{text}
</Text>
);
class Fix_bar extends Component {
state = { height: new Animated.Value(0) };
expand_dropdown = () => {
Animated.timing(this.state.height, {
toValue: 100
}).start();
}
fold_dropdown = () => {
Animated.timing(this.state.height, {
toValue: 0
}).start();
}
render () {
const s = {
position: 'absolute', height: 150, backgroundColor: 'red', paddingTop: 20, width
};
return (
<View style={s}>
<View style={{flexDirection: 'row', flex: 1, justifyContent: 'space-between'}}>
<Text style={{fontSize: 24, paddingTop: 50}}> Left side thing</Text>
<Text style={{fontSize: 24, paddingTop: 50}}> Right side thing</Text>
</View>
<Button title={'Expand'} onPress={this.expand_dropdown}/>
<Button title={'Fold'} onPress={this.fold_dropdown}/>
<View style={{backgroundColor: 'black', height: 1}}/>
<Animated.View style={{height: this.state.height}}>
{make_text('world', 'aliceblue')}
{make_text('world', 'aliceblue')}
{make_text('world', 'aliceblue')}
</Animated.View>
</View>
);
}
}
class animate_example extends Component {
render() {
return (
<View style={{backgroundColor: 'orange', flex: 1}}>
<Fix_bar/>
<ScrollView style={{marginTop: 150}}>
<View style={{justifyContent: 'space-between'}}>
{make_text()}
{make_text()}
{make_text()}
{make_text()}
{make_text()}
</View>
</ScrollView>
</View>
);
}
}
AppRegistry.registerComponent('animate_example', () => animate_example);
One idea I had was to make a trailing View in that fix_bar component with transparency with the height that I intend for the dropdown but haven't explored that idea.
I would suggest the following hierarchy:
const ScrollViewContainer = () =>
<ScrollView style={{marginTop: 150}}>
<View style={{justifyContent: 'space-between'}}>
{make_text()}
{make_text()}
{make_text()}
{make_text()}
{make_text()}
</View>
</ScrollView>;
const ExpandableBar = (props: {expanded: boolean}) =>
<View style={{position: "absolute", top: 0, left: 0, right: 0, bottom: 0}} />
const render = () =>
<View>
<Fix_bar />
<View style={{flex: 1}}> // container which fills remaining space
<ScrollViewContainer />
<ExpandableBar />
</View>
Then in ExpandableBar you'd animate down if expanded is true. also please note that ExpandableBar should be a class (obviously).