ReactNative封裝的優雅居中/底部彈出框

/*
 * @Date: 2019-08-30 16:05:37
 * @Description: 真的不想每次都寫個Modal了。
 * @Author: zhangji
 * @LastEditors: ZhangJi
 * @LastEditTime: 2019-09-02 11:16:51
 */

import React from "react";
import _ from "lodash";
import {
  View,
  StyleSheet,
  Component,
  Platform,
  ActivityIndicator,
  FlatList,
  Image,
  TouchableWithoutFeedback,
  TouchableOpacity,
  Text,
  Alert,
  Modal,
  RefreshControl,
  NativeModules,
  ScrollView,
  TekLoadingDialog,
  LayoutAnimation
} = 'react-native';


/**
 * 通用彈出框,包括居中彈出框和底部彈出框
 * @param {Boolean} isVisible 控制是否可見
 * @param {?Boolean} isBottomView 可選,控制是否爲底部彈出框樣式,默認爲居中彈出框
 * @param {?Boolean} isTouchMaskToClose 可選,控制是否點擊陰影關閉彈窗,默認開啓
 * @param {?String} title 可選,標題,默認爲`提示`,只對居中彈窗生效
 * @param {?String} confirmText 可選,居中框的確認按鈕描述,默認爲`確 認`
 * @param {?JSX} customTitleView 可選,自定義title樣式(包括居中和底部彈框),若該屬性有值,會覆蓋默認樣式,當需要自定義按鈕點擊功能時可以用這個,
 * @param {?JSX} customBottomView 可選,自定義底部樣式(包括居中和底部彈框),若該屬性有值,會覆蓋默認樣式,當需要自定義按鈕點擊功能時可以用這個,
 *
 * eg:` <MyModal
 *         isVisible={this.state.isVisible}
 *      >
 *          <Text>測試彈窗</Text>
 *      </MyModal>`
 */
export default class MyModal extends Component {
  constructor(props) {
    super(props);
    this.title = props.title || "提示";
    this.confirmText = props.confirmText || "確 認";
    this.customTitleView = props.customTitleView
      ? props.customTitleView
      : false;
    this.customBottomView = props.customBottomView
      ? props.customBottomView
      : false;
    this.isBottomView = !!JSON.stringify(props.isBottomView)
      ? this.props.isBottomView
      : false;
    this.isTouchMaskToClose = !!JSON.stringify(props.isTouchMaskToClose)
      ? this.props.isTouchMaskToClose
      : true;

    this.state = {
      isVisible: this.props.isVisible || false
    };
  }

  setModalVisiable(state) {
    this.setState({
      isVisible: state
    });
  }

  componentWillReceiveProps(newProps) {
    if (!_.isEmpty(this.props, newProps)) {
      if (this.state.isVisible != newProps.isVisible) {
        this.setState({
          isVisible: newProps.isVisible
        });
      }
    }
  }

  render() {
    return (
      <Modal
        animationType="fade"
        transparent={true}
        visible={this.state.isVisible}
        onRequestClose={() => {
          this.setModalVisiable(false);
        }}
      >
        {this.isBottomView ? (
          <View style={styles.bottomModalContainer}>
            <TouchableOpacity
              style={styles.bottomMask}
              onPress={() => {
                this.setModalVisiable(false);
              }}
            />
            <View style={styles.bottomContent}>{this.props.children}</View>
            {this.customBottomView ? (
              this.customBottomView
            ) : (
              <View style={styles.bottomBtns}>
                <TouchableOpacity
                  onPress={() => {
                    this.setModalVisiable(false);
                  }}
                >
                  <View
                    style={[
                      styles.bottomBtnsView,
                      { borderWidth: 0.5, borderColor: "#999" }
                    ]}
                  >
                    <Text
                      style={[
                        styles.bottomBtnsText,
                        { color: "#333", fontFamily: "PingFangSC-Light" }
                      ]}
                    >
                      取消
                    </Text>
                  </View>
                </TouchableOpacity>
                <TouchableOpacity onPress={() => {}}>
                  <View
                    style={[
                      styles.bottomBtnsView,
                      {
                        backgroundColor: "#417EFF",
                        borderWidth: 0.5,
                        borderColor: "#417EFF"
                      }
                    ]}
                  >
                    <Text
                      style={[
                        styles.bottomBtnsText,
                        { color: "#fff", fontWeight: "bold" }
                      ]}
                    >
                      確定
                    </Text>
                  </View>
                </TouchableOpacity>
              </View>
            )}
          </View>
        ) : (
          <View style={styles.modalContainer}>
            <TouchableWithoutFeedback
              onPress={() => {
                this.isTouchMaskToClose ? this.setModalVisiable(false) : null;
              }}
            >
              <View style={styles.mask} />
            </TouchableWithoutFeedback>
            <View style={styles.container}>
              {this.customTitleView ? (
                this.customTitleView
              ) : (
                <Text style={styles.title}>{this.title}</Text>
              )}
              {this.props.children}
              <View
                style={{
                  height: 0.5,
                  width: appConfig.ScreenWidth - 42,
                  backgroundColor: "#E5E5E5"
                }}
              />
              {this.customBottomView ? (
                this.customBottomView
              ) : (
                <TouchableOpacity onPress={() => this.setModalVisiable(false)}>
                  <Text style={styles.confirmBtn}>{this.confirmText}</Text>
                </TouchableOpacity>
              )}
            </View>
          </View>
        )}
      </Modal>
    );
  }
}

const styles = StyleSheet.create({
  modalContainer: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    width: appConfig.ScreenWidth,
    height: appConfig.ScreenHeight
  },
  mask: {
    width: appConfig.ScreenWidth,
    height: appConfig.ScreenHeight,
    backgroundColor: "rgba(0,0,0,.4)",
    position: "absolute",
    left: 0,
    top: 0
  },
  container: {
    width: appConfig.ScreenWidth - 30,
    backgroundColor: "#FFF",
    borderTopLeftRadius: 9,
    borderTopRightRadius: 9,
    borderBottomLeftRadius: 9,
    borderBottomRightRadius: 9,
    justifyContent: "center",
    alignItems: "center"
  },
  title: {
    textAlign: "center",
    fontFamily: "PingFangSC-Semibold",
    fontSize: 16,
    color: "#333",
    marginTop: 18
  },
  confirmBtn: {
    color: "#417EFF",
    fontSize: 17,
    fontFamily: "PingFangSC-Semibold",
    marginBottom: 18,
    marginTop: 14.2,
    width: appConfig.ScreenWidth - 42,
    textAlign: "center"
  },

  bottomModalContainer: {
    flex: 1,
    justifyContent: "flex-end",
    width: appConfig.ScreenWidth,
    height: appConfig.ScreenHeight
  },
  bottomMask: {
    flex: 1,
    width: appConfig.ScreenWidth,
    marginBottom: -9,
    backgroundColor: "rgba(0,0,0,.4)"
  },
  content: {
    width: appConfig.ScreenWidth,
    backgroundColor: "#FFF",
    borderTopLeftRadius: 9,
    borderTopRightRadius: 9,
    paddingTop: 15
  },
  bottomBtns: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-around",
    backgroundColor: "#fff",
    marginBottom: appConfig.StatusBarHeight == 44 ? 34 : 0,
    shadowColor: "#00000033",
    shadowOffset: { width: 0, height: -9 },
    shadowOpacity: 0.1,
    shadowRadius: 6,
    elevation: 10
  },
  bottomBtnsView: {
    width: 165,
    height: 42,
    borderRadius: 100,
    marginTop: 12,
    marginBottom: 12,
    justifyContent: "center",
    alignItems: "center"
  },
  bottomBtnsText: {
    fontSize: 16
  },
  bottomModalContainer: {
    flex: 1,
    justifyContent: "flex-end",
    width: appConfig.ScreenWidth,
    height: appConfig.ScreenHeight
  },
  bottomMask: {
    flex: 1,
    width: appConfig.ScreenWidth,
    backgroundColor: "#33333344",
    marginBottom: -9
  },
  bottomContent: {
    width: appConfig.ScreenWidth,
    backgroundColor: "#FFF",
    borderTopLeftRadius: 9,
    borderTopRightRadius: 9,
    paddingTop: 15
  }
});

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章