"react-native-loading-spinner-overlay" is not working when modal is open in iOS - react-native

"react-native-loading-spinner-overlay" is not working when modal is open in iOS. If I set modal visible to false, it works.
(Android is working well in any case.)
That is my code.
When modal is open, if I click upload button on modal,
_onUpload = () => {
this.setState({ isLoading: true }) //-----> Loading spinner is not working.
}
If I make like this
_onUpload = () => {
this.setState({ modalVisible:false }) //-----> After modal turns off
setTimeout(() => {
this.setState({ isLoading: true }) //----> Loading spinner works.
}, 500);
}
render
render() {
return (
<View>
<Spinner
visible={this.state.isLoading}
textContent={'Loading...'}
textStyle={{ color: 'white' }}
/>
</View>
)
}
I used modal from 'react-native-modal'
import Modal from 'react-native-modal';
<Modal
isVisible={modalVisible}
backdropColor="#B4B3DB"
backdropOpacity={0.8}
animationIn="zoomInDown"
animationOut="zoomOutUp"
animationInTiming={1000}
animationOutTiming={1000}
backdropTransitionInTiming={1000}
backdropTransitionOutTiming={1000}>
<View style={styles.modalBody}>
<TouchableOpacity onPress={() => this._onUpload()} >
<Text>Upload</Text>
</TouchableOpacity>
</View>
</Modal>
Why it is not working on only iOS?
How to make it work on iOS when modal is open?

You cannot use one Modal on another Modal in ios,
you have to close the first Modal before opening a second Modal.
like,
setstate({isLoading:false,modalVisible:true})
or you can use ternary like,
{modalVisible?
<View style={styles.modalBody}>
<TouchableOpacity onPress={() => this._onUpload()} >
<Text>Upload</Text>
</TouchableOpacity>
</View: null}

Add a timeout to wait for the first Modal to close.
setTimeout(() => {
setstate({modalVisible:true})
}, 2000);

Creating your own spinner is the best option I come across for this issue.
{showSpinner && (
<View style={{ ...StyleSheet.absoluteFill, zIndex: 1 }}>
<ActivityIndicator color={Colors.gray900} size="large" style={{ flex: 1, backgroundColor: Colors.gray300, opacity: 0.3 }} />
</View>
)}

Related

Need to double press to release focus on Text Input from within a Modal with KeyboardAvoidingView

I have a Modal wrapping a KeyboardAvoidingView wrapping a few animated components. One of them is a TextInput and the other is a Button. When clicking on the button, keyboard is first hidden, and then need to click once again to reach the buttons "onPress"
Looked into the solution of wrapping the components with a scroll view and using a the prop keyboardShouldPersistTaps={'always'} but that doesn't work.
constructor(props) {
super(props);
this.paddingInput = new Animated.Value(0);
this.state = {
modalVisible: false,
otherTip: '',
}
}
renderHoveringNote = () => {
const {total, currentTipPercent} = this.props.rootStore.orderStore;
return (
<View>
<KeyboardAvoidingView style={{flex: 1}}>
<Animated.View style={{
marginBottom: this.paddingInput,
flex: 1
}}>
<View>
<Text>Enter custom amount</Text>
</View>
<TextInput
onChangeText={value => {
this.setState({otherTip: value})
}}
autoFocus
value={this.state.otherTip}
/>
<Button title='Save'
onPress={()=>{
...do some stuff here
this.setState({modalVisible: false});
Keyboard.dismiss();
}}
</Animated.View>
</KeyboardAvoidingView>
</View>
)
};
renderOtherTipModal = () => {
return (
<Modal
isVisible={this.state.modalVisible}
onBackdropPress{()=>this.setState({modalVisible:false})}
style={{margin: 0, flex: 1}}
hideModalContentWhileAnimating={true}
>
{this.renderHoveringNote()}
</Modal>
)
};
One click should reach the onPress of the button
Figured it out - I had a few Scroll Views as parents to the Modal. It is important to have ALL of the parent Scroll Views to have keyboardShouldPersistTaps={'always'}.
After adding that, it worked great.

How can I use tabs in a modal in react-native

I have modal for filtering search resluts , something like foursquare app . I have filters in diffrent categories and I need to use tabs for each category . for example when user clicks each tabs it shows the filters related to that tab . and user can select checkboxes or radio buttons . and at the end when user checks all of their needed filters I need to make http request with the new filters.
Something like the image below . I created the modal but I need the functionality for tabs and at the end making the api request with the selected options:
You can also create custom tabs using <Text> with state and depending on a state value render a View associated with that tab. for example
state = {
modalVisible: false,
currentTab: 1,
};
onTabClick = (currentTab) => {
this.setState({
currentTab: currentTab,
});
};
// inside render
<Modal
animationType="slide"
transparent={true}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={styles.tabs}>
<Text
onPress={() => {
this.onTabClick(1);
}}
style={[
styles.tabTextStyle,
this.state.currentTab === 1 ? styles.tabUnderline : null,
]}>
GENDER
</Text>
...
</View>
{this.state.currentTab === 1 && (
<View>
<Text>GENDER</Text>
</View>
)}
...
snack example
Modal is just a Container like View. You can draw anything inside it.
First, import {Modal} from 'react-native'
Then, in your modal, embed anything what you want:
<Modal visible={ this.state.modal }
animationType="fade" transparent={true}
onRequestClose={_ => this.setState({ modal: false }) }>
<View>
{/*
Do anything. Its an open ground.
Whatever component, styles, props and/or anything else you want, you can design
*/}
{/* For example, I am adding a close button */}
<TouchableOpacity style={{ alignSelf: 'flex-end' }} onPress={_ => this.setState({ modal: false }) }>
<Icon type="FontAwesome" name='times' style={ styles.closeIcon } />
</TouchableOpacity>
</View>
</Modal>
And you can open your modal from anywhere like:
<TouchableOpacity style={ styles.button } onPress={_ => this.setState({ modal: true }) }>
<Text style={ styles.buttonText }>Open Modal</Text>
</TouchableOpacity>
Finally, for tabs, you can use either of:
NativeBase Tab Component
React Native Tab View

React-Native Controlled Modal Freezing

Disclaimers:
Only can test on iPhone emulator atm.
React-Native 0.49
Mac OSX High Sierra
I want to create a modal which gets its props from a parent component.
As below:
const Modal = ({ showModal, closeModal }) => (
<Modal
animationType="slide"
transparent={false}
visible={showModal}
onRequestClose={() => {alert("Modal has been closed.")}}
>
<View style={{marginTop: 22}}>
<Text>Hello World!</Text>
<TouchableHighlight onPress={() => closeModal() }>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</Modal>
);
This is the parent example:
<View>
<Modal
showModal={this.state.showModal}
closeModal={() => this.setState({ showModal: false })}
/>
<ScrollView>
{elements.map(element => {
return (
<Card key={element.id}>
<Badge onPress={() => this.setState({ showModal: true })>
<Text>Show</Text>
</Badge>
</Card>
);
})}
</ScrollView>
</View>
When I click the show modal button the modal pops-up as expected but when I click closeModal then the modal disappears and reappears again but this time I cannot interact with it, the UI seems as if it is frozen, I have to then restart the emulator.
If I copy and paste the code straight from the React-Native docs:
https://facebook.github.io/react-native/docs/modal.html
The modal works fine. It is a self-contained component though.
Any help/advice would be much appreciated.
Regards,
Emir
After painfully rebuilding the component from scratch I see there was a unsuspected culprit:
componentWillUpdate() {
UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
LayoutAnimation.easeInEaseOut();
}
When I removed this code the modal worked fine but when I added it back it froze when I tried to close. This seems to be some animation conflict in iOS cant confirm for Android.
When I added a timeout of 1000ms the screen revealed a little more before it froze again.
So for now if someone has the same issue look for multiple animations being called.
Hope this helps someone, and if you have a better way of solving it please do let me know.
Regards,
Emir
This is a know issue and nothing to do with your code.
See here: https://github.com/facebook/react-native/issues/16895
Make sure that your <Modal/> is wrapped in a <View/>.
Very late, but issue still exist in latest version, And only solution i found is make different views in render method.
one for modal and one for other component.
render() {
if (showErrorModal) {
return (
<ModalError message={message} visible={showErrorModal} handleBack={this.handleBack} />
);
}
return (
<ScrollView style={{ flex: 1 }}>
<View style={{ padding: 10, paddingVertical: 20 }}>
{!active ? this.fieldlabel() : this.fieldSelect()}
</View>
// remove this one, do not use here. it will block the UI
{* <ModalError message={message} visible={showErrorModal} handleBack={this.handleBack} /> *}
</ScrollView>
);
}
}
Inside your Parent component, create a function will set showModal to false.
Parent
closeModal = () => {
this.setState({
showModal: false
});
}
Then you need to pass it down to your Modal, via props.
<Modal showModal={this.state.showModal} closeModal={this.closeModal} />
Inside of your Modal, change:
<TouchableHighlight onPress={() => this.closeModal() }>
To:
<TouchableHighlight onPress={closeModal}>
Why do u use this.closeModal()? Use the one u are getting from the props,i.e just closeModal().
<TouchableHighlight onPress={() => closeModal() }>

Modal doesn't work with LayoutAnimation on iPhone

This is what I'm trying to do, basically, click Open Modal button to open modal, then click Close Modal button inside modal to close it. The two pictures below are how both cases should look like.
This is my code:
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false
};
}
componentWillUpdate() {
if(PlatForm.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
LayoutAnimation.easeInEaseOut();
}
render() {
return (
<View style={{ ... }}>
<TouchableOpacity onPress={() => this.setState({ showModal: true })}>
<Text style={{ ... }}>
Open Modal
</Text>
</TouchableOpacity>
<Modal visible={this.state.showModal} animationType='slide'>
<View style={{ ... }}>
<TouchableOpacity onPress={() => this.setState({ showModal: false })}>
<Text style={{ color: 'white', fontSize: 20 }}>
Close Modal
</Text>
</TouchableOpacity>
</View>
</Modal>
</View>
);
}
}
Everything works as expected when running on an IOS simulator, but problems rises when running on an iPhone. When press Close Modal, modal disappears for like half a second, then reopens itself again, and this time, Close Modal button won't work, I cannot re-close modal. All I can do is to re-build project. However, when I delete componentWillUpdate(), it works again, both on simulator and on iPhone
I believe this is a bug introduced in a recent version of React Native. Your best bet, for now, is to disable LayoutAnimation. Not ideal...I know.
See the discussion on Github here: https://github.com/facebook/react-native/issues/16182

React-native-popup-menu on react-navigation header

I'm using redux with react-navigation and would like to show the popup when the user clicks on the button on the react-navigation header-right button.
I wrapped the context menu at the root of my apps, as below
return (
<Provider store={store}>
<MenuContext style={{ flex: 1 }}>
<AppWithNavigationState />
</MenuContext>
</Provider>
)
in one of my screen, I have
static navigationOptions = {
headerTitle: 'News',
headerRight: (
<TouchableOpacity style={{ paddingLeft:15, paddingRight:15 }}>
<Icon name="more-vert" size={30} color="black" />
</TouchableOpacity>
),
}
When the user clicks on the right button, it should be like this
The menu items are dynamic, I will have to pull the data from one of my API and start rendering the menu data.
I've read through online it can be achieved using the context method, but I'm not sure how to implement it in my structure.
Could anyone advise me on this?
And is it possible to render it with my local variable?
The most custom way is to use Modal, when click the right button, called this.refs.modalRef.showModal(), which in your current page:
<View>
<PopupModal ref="modalRef" />
</View>
The PopupModal like this:
export default class PopupModal extends Component {
state = {
show: false,
}
showModal() {
this.setState({show: true});
}
closeModal = () => {
this.setState({show: false});
}
return (
<Modal
transparent
visible={this.state.show}
onRequestClose={this.closeModal}
>
<TouchableWithoutFeedback onPress={this.closeModal}>
<View style={{
width: '100%',
height: '100%',
opacity: 0.5,
backgroundColor: 'gray',
}} />
</TouchableWithoutFeedback>
<View></View> // your designed view, mostly position: 'absolute'
</Modal>
);
}
You can also pass some data to PopupModal by this.refs.modalRef.showModal(data), and in PopupModal:
showModal = (data) => {
this.setState({ data, show: true });
}
https://www.npmjs.com/package/react-native-material-menu
It works to me
headerRight:<View style={{marginRight:10}}>
<Menu
ref={this.setMenuRef}
button={<Text onPress={this.showMenu}><Icon style={{color:screenProps.headerTitleStyle.color,fontSize:25,marginRight:5}} name="md-more"/></Text>}
>
<MenuItem onPress={this.hideMenu}>Rate Us</MenuItem>
<MenuItem onPress={this.hideMenu}>Share App</MenuItem>
<MenuItem onPress={this.hideMenu}>Settings</MenuItem>
</Menu>
</View>,