rn-gnavigator
Version:
Simple stack navigator
217 lines (215 loc) • 8.03 kB
JavaScript
import React from 'react';
import { View, Dimensions, Animated, BackHandler, AsyncStorage } from 'react-native';
const { width, height } = Dimensions.get('screen');
type Props = {};
export default class Stack extends React.Component<Props> {
static defaultProps = {
initialScreen: <View />,
initialParam: '',
initialScreenBackHandler: () => BackHandler.exitApp(),
transitionDirection: 'horizontal',
transitionDuration: 200,
transition: 'none',
type: 'normal',
loginScreen: <View />,
homeScreen: <View />,
loginParam: '',
logoutParam: ''
};
constructor(prop) {
super(prop);
this.state = {
screen: [],
state: {}
};
}
componentWillMount() {
AsyncStorage.getItem('appLogin', (err, res) => {
let Screen;
if (res != null) {
const login = JSON.parse(res);
if (login) {
Screen = this.props.homeScreen;
} else {
Screen = this.props.loginScreen;
}
} else {
Screen = this.props.loginScreen;
}
switch (this.props.type) {
case 'normal': this.push({ Screen: this.props.initialScreen, param: this.props.initialParam }); break;
case 'auth': this.push({ Screen, param: this.props.loginParam }); break;
default: break;
}
});
// if (this.props.initialScreen != undefined) {
// this.push({ Screen: this.props.initialScreen, param: this.props.initialParam });
// }
BackHandler.addEventListener('hardwareBackPress', () => {
if (this.state.screen.length > 1) {
this.pop();
} else {
this.props.initialScreenBackHandler();
}
return true;
});
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress');
}
push({ Screen, param }) {
const screen = this.state.screen;
const l = screen.length;
let left, right, top, bottom, opacity;
const duration = this.props.transitionDuration;
switch (this.props.transitionDirection) {
case 'horizontal':
left = new Animated.Value(width);
right = new Animated.Value(-width);
top = new Animated.Value(0);
bottom = new Animated.Value(0);
break;
case 'vertical':
left = new Animated.Value(0);
right = new Animated.Value(0);
top = new Animated.Value(height);
bottom = new Animated.Value(-height);
break;
case 'normal':
left = new Animated.Value(0);
right = new Animated.Value(0);
top = new Animated.Value(0);
bottom = new Animated.Value(0);
break;
default: break;
}
switch (this.props.transition) {
case 'none': opacity = new Animated.Value(1); break;
case 'fade': opacity = new Animated.Value(0); break;
default: break;
}
screen.push({ Screen, left, right, top, bottom, opacity, param });
this.setState({ screen });
setTimeout(() => {
Animated.parallel([
Animated.timing(screen[l].left, {
toValue: 0, duration
}),
Animated.timing(screen[l].right, {
toValue: 0, duration
}),
Animated.timing(screen[l].top, {
toValue: 0, duration
}),
Animated.timing(screen[l].bottom, {
toValue: 0, duration
}),
Animated.timing(screen[l].opacity, {
toValue: 1, duration
})
]).start();
}, 1);
}
pop() {
const screen = this.state.screen;
const l = screen.length - 1;
const duration = this.props.transitionDuration;
let opacity;
switch (this.props.transition) {
case 'none': opacity = 1; break;
case 'fade': opacity = 0; break;
default: break;
}
switch (this.props.transitionDirection) {
case 'horizontal':
Animated.parallel([
Animated.timing(screen[l].left, {
toValue: width, duration
}),
Animated.timing(screen[l].right, {
toValue: -width, duration
}),
Animated.timing(screen[l].opacity, {
toValue: opacity, duration
})
]).start(() => {
screen.pop();
this.setState({ screen: screen });
});
break;
case 'vertical':
Animated.parallel([
Animated.timing(screen[l].top, {
toValue: height, duration
}),
Animated.timing(screen[l].bottom, {
toValue: -height, duration
}),
Animated.timing(screen[l].opacity, {
toValue: opacity, duration
})
]).start(() => {
screen.pop();
this.setState({ screen: screen });
});
break;
case 'normal':
screen.pop();
this.setState({ screen: screen });
break;
default: break;
}
}
restart() {
const screen = [this.state.screen[0]];
this.setState({ screen: [] });
setTimeout(() => this.setState({ screen }), 1);
}
login() {
const screen = [{ Screen: this.props.homeScreen, param: this.props.loginParam }];
this.setState({ screen: [] });
AsyncStorage.setItem('appLogin', 'true').then(() => {
setTimeout(() => this.setState({ screen }), 1);
});
}
logout() {
const screen = [{ Screen: this.props.loginScreen, param: this.props.logoutParam }];
this.setState({ screen: [] });
AsyncStorage.setItem('appLogin', 'false').then(() => {
setTimeout(() => this.setState({ screen }), 1);
});
}
setComponentState(param) {
this.setState({
state: {
...this.state.state,
...param
}
});
}
render() {
const screen = this.state.screen;
const l = screen.length - 1;
const style = {
position: 'absolute',
width,
height
}
return (
<View style={{ flex: 1 }}>
{screen.map(({ Screen, left, right, top, bottom, opacity, param }, i) => <Animated.View key={i} style={{ ...style, left, opacity, right, top, bottom, zIndex: l === i ? i + 10 : i, elevation: l === i ? i + 10 : i }}>
<Screen
state={this.state.state}
setState={param => this.setComponentState(param)}
push={(page) => this.push(page)}
restart={() => this.restart()}
pop={() => this.pop()}
pushedData={param}
login={() => this.login()}
logout={() => this.logout()}
/>
</Animated.View>)}
</View>
);
}
}