Reputation: 121
In react native, can we achieve a UI where there are multiple screens stacked on top of each other with each screen stacking on top of the other on click of a button.
Let's say, there is Screen A. Upon click of a button, Screen B is placed as a stack on Screen A and screen A is still partly visible as Screen B doesn't occupy the entire screen layout. Similarly, Screen C adds up to the stack upon the click of a button in Screen B and screen B is still visible along with screen A in the background. All these come with a side animation from the left (similar to navigation drawer). With a common button, all the above screens can be popped out from the stack and the previous screen comes to the top with a side animation again, this time to the right.
I wanted to understand if the above is possible in react native? If yes, how I can achieve it? I wish I can show the design but I cannot do that atm.
Upvotes: 0
Views: 2370
Reputation: 121
I could achieve this functionality using a very cool library named 'react-native-modalfy'.
import React, { PureComponent } from 'react'
import {
Easing,
Dimensions,
StatusBar,
StyleSheet,
Text,
View,
} from 'react-native'
import { ModalProvider, createModalStack } from 'react-native-modalfy'
import CardModal from './modals/CardModal'
import Button from './components/Button'
const { width } = Dimensions.get('screen')
const config = { ModalA: CardModal, ModalB: CardModal, ModalC: CardModal }
const defaultOptions = {
transitionOptions: animatedValue => ({
opacity: animatedValue.interpolate({
inputRange: [0, 1, 2],
outputRange: [0, 1, .9],
}),
transform: [
{
perspective: 2000
},
{
translateX: animatedValue.interpolate({
inputRange: [0, 1, 2],
outputRange: [-width / 2, 0, 25],
}),
},
{
scale: animatedValue.interpolate({
inputRange: [0, 1, 2],
outputRange: [1.2, 1, .9],
}),
},
],
}),
animateInConfig: {
easing: Easing.bezier(.42,-0.03,.27,.95),
duration: 450,
},
animateOutConfig: {
easing: Easing.bezier(.42,-0.03,.27,.95),
duration: 450,
},
}
const stack = createModalStack(config, defaultOptions)
class App extends PureComponent {
render() {
return (
<ModalProvider stack={stack}>
<View style={styles.container}>
<StatusBar animated hidden translucent />
<Text style={styles.title}>RNM</Text>
<Button label="Open ModalA" modalToOpen="ModalA" color="tomato" />
<Button label="Open ModalB" modalToOpen="ModalB" color="darkcyan" />
<Button label="Open ModalC" modalToOpen="ModalC" color="deeppink" />
</View>
</ModalProvider>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'indigo',
alignItems: 'center',
justifyContent: 'center'
},
title: {
color: 'white',
fontSize: 54,
fontWeight: 'bold',
marginBottom: 50,
},
})
export default App
import React, { PureComponent } from 'react'
import {
Button as ButtonModule,
Dimensions,
StyleSheet,
Text,
View,
} from 'react-native'
import Button from '../components/Button'
const { width: ww, height: wh } = Dimensions.get('screen')
class CardModal extends PureComponent {
componentDidMount() {
const { modal } = this.props
this.modalListenerID = modal.addListener('onAnimate', this._handleAnimation)
}
componentWillUnmount() {
this.modalListenerID?.remove()
}
_handleAnimation = animatedValue => {
const { currentModal } = this.props.modal
console.info(`${currentModal}:`, animatedValue)
}
render() {
const {
currentModal,
closeModal,
closeModals,
closeAllModals,
params: { color },
} = this.props.modal
return (
<View style={[styles.card]}>
<Text style={styles.title(color)}>{currentModal}</Text>
<Button label="Open ModalA" modalToOpen="ModalA" color="tomato" />
<Button label="Open ModalB" modalToOpen="ModalB" color="darkcyan" />
<Button label="Open ModalC" modalToOpen="ModalC" color="deeppink" />
<ButtonModule title="Close" onPress={closeModal} color="dodgerblue" />
<ButtonModule title={`Close all ${currentModal}`} onPress={() => closeModals(currentModal)} color="dodgerblue" />
<ButtonModule title="Close all modals" onPress={closeAllModals} color="red" />
</View>
)
}
}
const styles = StyleSheet.create({
title: color => ({
color,
fontSize: 48,
fontWeight: 'bold',
marginBottom: 50,
}),
card: {
marginRight : 90,
width: ww,
height: wh,
backgroundColor: 'cyan',
elevation: 0,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 0,
},
})
export default CardModal
import React, { PureComponent } from 'react'
import { TouchableOpacity, StyleSheet, Text } from 'react-native'
import { withModal } from 'react-native-modalfy'
class Button extends PureComponent {
openModal = () => {
const { color, modalToOpen, modal } = this.props
modal.openModal(modalToOpen, { color })
}
render() {
const { color, label } = this.props
return (
<TouchableOpacity onPress={this.openModal} style={styles.button(color)}>
<Text style={styles.label}>{label}</Text>
</TouchableOpacity>
)
}
}
const styles = StyleSheet.create({
button: backgroundColor => ({
backgroundColor,
paddingHorizontal: 60,
paddingVertical: 21,
borderRadius: 21,
marginBottom: 30,
}),
label: {
fontSize: 16,
fontWeight: '800',
color: 'white',
textAlign: 'center',
},
})
export default withModal(Button)
Upvotes: 0
Reputation: 2972
With react-native-vertical-view-pager you can do it.
install with:
npm install --save react-native-vertical-view-pager
or with yarn (if you use yarn):
yarn add react-native-vertical-view-pager
and use as follow:
import React from 'react';
import { StyleSheet, Text, View, Dimensions } from 'react-native';
import VerticalViewPager from 'react-native-vertical-view-pager';
const { width, height } = Dimensions.get('window');
export default class App extends React.Component {
render() {
return (
<VerticalViewPager
showsVerticalScrollIndicator={false}>
<View style={[styles.page_container, {backgroundColor: 'pink'}]}>
<Text>Page1: Open up App.js to start working on your app!</Text>
</View>
<View style={[styles.page_container, {backgroundColor: 'olive'}]}>
<Text>Page2: Changes you make will automatically reload.</Text>
</View>
<View style={[styles.page_container, {backgroundColor: 'lightblue'}]}>
<Text>Page3: Shake your phone to open the developer menu.</Text>
</View>
</VerticalViewPager>
);
}
}
const styles = StyleSheet.create({
page_container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
width,
height
}
});
with your screens on the place of the views.
Upvotes: 1