UNPKG

3.18 kBJavaScriptView Raw
1/**
2 * 遮罩层
3 * @CopyLeft [rnx-ui](https://github.com/rnxteam/rnx-ui/tree/master/Overlay)
4 */
5import React, {
6 PropTypes,
7 Component,
8} from 'react';
9import {
10 StyleSheet,
11 Animated,
12 TouchableWithoutFeedback,
13 View,
14 Modal,
15} from 'react-native';
16
17const NOOP = () => {};
18
19const styles = StyleSheet.create({
20 all: {
21 position: 'absolute',
22 left: 0,
23 right: 0,
24 top: 0,
25 bottom: 0,
26 backgroundColor: 'rgba(0, 0, 0, 0.4)',
27 },
28});
29
30class Overlay extends Component {
31 constructor(props) {
32 super(props);
33
34 const visible = props.visible;
35
36 this.state = {
37 visible,
38 opacity: new Animated.Value(visible ? 1 : 0),
39 };
40
41 this.aniShow = Animated.timing(this.state.opacity, {
42 toValue: 1,
43 duration: props.duration,
44 });
45 this.aniHide = Animated.timing(this.state.opacity, {
46 toValue: 0,
47 duration: 200,
48 });
49 }
50
51 componentWillReceiveProps(props) {
52 if (props.visible && !this.props.visible) {
53 // 隐藏 -> 显示
54 this.show();
55 } else if (!props.visible && this.props.visible) {
56 // 显示 -> 隐藏
57 this.hide();
58 }
59 }
60
61 // 显示
62 show() {
63 if (this.props.useAnimation) {
64 this.aniHide.stop();
65 }
66
67 this.setState({
68 visible: true,
69 });
70
71 if (this.props.useAnimation) {
72 this.aniShow.start();
73 }
74 }
75
76 // 隐藏
77 hide() {
78 if (this.props.useAnimation) {
79 this.aniHide.stop();
80 this.aniHide.start(() => {
81 this.setState({
82 visible: false,
83 });
84 });
85 } else {
86 this.setState({
87 visible: false,
88 });
89 }
90 }
91
92 render() {
93 if (!this.state.visible) {
94 return null;
95 }
96
97 return (
98 <Modal
99 animationType="none"
100 onRequestClose={NOOP}
101 transparent
102 visible={this.state.visible}
103 >
104 <TouchableWithoutFeedback
105 onPress={this.props.onPress}
106 >
107 {this.props.useAnimation ? (
108 <Animated.View
109 style={[styles.all, {
110 opacity: this.state.opacity,
111 }, this.props.style]}
112 pointerEvents={this.props.pointerEvents}
113 />
114 ) : (
115 <View
116 style={[styles.all, this.props.style]}
117 pointerEvents={this.props.pointerEvents}
118 />
119 )}
120 </TouchableWithoutFeedback>
121 {this.props.children}
122 </Modal>
123 );
124 }
125}
126
127Overlay.propTypes = {
128 // 显示开关
129 visible: PropTypes.bool.isRequired,
130 // 点击回调
131 onPress: PropTypes.func,
132 // 自定义样式
133 style: View.propTypes.style,
134 // 子元素
135 children: PropTypes.oneOfType([PropTypes.element, PropTypes.array]),
136 // 控制 Overlay 是否可以作为触控事件的目标(参考 https://facebook.github.io/react-native/docs/view.html#pointerevents)
137 pointerEvents: View.propTypes.pointerEvents,
138 // 动画时长
139 duration: PropTypes.number,
140 // 是否使用动画
141 useAnimation: PropTypes.bool,
142};
143Overlay.defaultProps = {
144 visible: false,
145 onPress: NOOP,
146 style: null,
147 children: null,
148 pointerEvents: 'auto',
149 duration: 200,
150 useAnimation: true,
151};
152
153export default Overlay;