美文网首页
react native 弹框设计,兼容IOS和Android

react native 弹框设计,兼容IOS和Android

作者: 随遇而安_2750 | 来源:发表于2017-05-02 17:28 被阅读522次

1.实现的效果

- 点击按钮,出现弹框,最好有动画;

- 点击弹框周围,弹框消失;

- 点击Android返回键,弹框消失;

- 有“取消”和“确定”按钮,回调函数,巴拉巴拉巴。。。。

2.实现思路

- 弹框外层组件使用Modal,免得监听安卓返回键;

- 动画使用Animated;

- 最外层(绝对定位)存在一个宽高等于手机屏幕的activeOpacity=1的TouchableOpacity,点击能够使Modal消失;

3.源码

Popover.js

/**
 * 弹框 
 * @flow
 */

import React, { Component } from 'react';
import {
  Platform,
  StyleSheet,
  Text,
  View,
  BackHandler,
  Modal,
  Button,
  TouchableOpacity,
  Animated,
  Image,
  StatusBar
} from 'react-native';

import PropTypes from 'prop-types';
import theme from '../utils/theme';
const {screenWidth, screenHeight, segment} = theme;

export default class Popover extends Component {
  
  constructor(props){
    super(props);
    this.state = {
      show: false,
      pageX: 0,
      pageY: 0,
      height: 0,
      scaleAnimationValue: new Animated.Value(0)
    }
  }
  // 打开弹框
  showModal() {
    this.setState({
      show: true,
    });

    if(this.props.useAnimation){
      Animated.spring(this.state.scaleAnimationValue, {
          toValue: 1,
          duration: 200,
      }).start();
    }

  }
  // 关闭弹框
  onRequestClose() {
    if(this.props.useAnimation){
      this.state.scaleAnimationValue.setValue(0);
    }
    this.setState({
      show: false
    });
  }

  render() {
    const {hasCancelBtn, cancelCallback, title, content, ensureCallback, useAnimation, takePicsCallback, albumCallback, wordsCallback, hasWordBtn} = this.props;
    return (
      <View style={styles.modalContainer}>
        <Modal 
            animationType={"none"}
            transparent={true}
            visible={this.state.show}
            onRequestClose={() => this.onRequestClose()}>

          <TouchableOpacity 
            activeOpacity={1} 
            style={styles.modalContainer}
            onPress={() => this.onRequestClose()}
          >
            <View style={styles.outerContainer} />
          </TouchableOpacity>

          <Animated.View style={[styles.container, {transform: [{scale: useAnimation ? this.state.scaleAnimationValue : 1}]}]}>
            <View
                style={styles.promptContainer}
            >
              
              {
                this.props.onlyInChose ?
                <View style={styles.choseContainer}>
                  <TouchableOpacity activeOpacity={0.75} onPress={takePicsCallback}>
                    <View style={styles.choseItem}>
                      <Image source={require('../img/camera_small.png')} style={{width: theme.scaleSize(50),height: theme.scaleSize(40), resizeMode:'contain'}} />
                      <Text style={{color: '#343434',fontSize: theme.setSpText(32)}}>拍摄照片</Text>
                      <View style={{width: theme.scaleSize(48),height: theme.scaleSize(40)}} />
                    </View>
                  </TouchableOpacity>
                  <TouchableOpacity activeOpacity={0.75} onPress={albumCallback}>
                    <View style={[styles.choseItem, {borderBottomWidth: hasWordBtn ? segment.width : 0}]}>
                      <Image source={require('../img/page_small.png')} style={{width: theme.scaleSize(50),height: theme.scaleSize(40), resizeMode:'contain'}} />
                      <Text style={{color: '#343434',fontSize: theme.setSpText(32)}}>相册选择</Text>
                      <View style={{width: theme.scaleSize(48),height: theme.scaleSize(40)}} />
                    </View>
                  </TouchableOpacity>
                  {
                    hasWordBtn &&
                    <TouchableOpacity activeOpacity={0.75} onPress={wordsCallback}>
                      <View style={[styles.choseItem, {borderBottomWidth: 0}]}>
                        <Image source={require('../img/Text_small.png')} style={{width: theme.scaleSize(50),height: theme.scaleSize(40), resizeMode:'contain'}} />
                        <Text style={{color: '#343434',fontSize: theme.setSpText(32)}}>文字说说</Text>
                        <View style={{width: theme.scaleSize(48),height: theme.scaleSize(40)}} />
                      </View>
                    </TouchableOpacity>
                  }
                </View>
                :
                <View>
                  <View style={styles.titleContainer}>
                    <Text style={{color: '#333333',fontSize: theme.setSpText(38)}}>{title}</Text>
                  </View>

                  <View style={styles.contentContainer}>
                    <Text style={{color: '#343434',fontSize: theme.setSpText(34)}}>{content}</Text>
                  </View>
                </View>
              }
                
            </View>
            {
              this.props.onlyInChose ? 
              null
              :
              <View style={styles.buttonContainer}>
                {
                  hasCancelBtn && 
                  <TouchableOpacity
                      activeOpacity={0.75}
                      style={[styles.center, {flex: 4.5}]}
                      onPress={() => {
                        this._close();
                        // 取消后的事件
                        cancelCallback && cancelCallback()
                      }}
                  >
                      <Text style={{fontSize: theme.setSpText(38), color: '#666666'}}>取消</Text>
                  </TouchableOpacity>
                }
                <View style={[styles.line]}/>
                <TouchableOpacity
                    activeOpacity={0.75}
                    style={[styles.center, {flex: 4.5}]}
                    onPress={() => {
                        this.onRequestClose();
                        // 子组件传递数据到父组件 
                        ensureCallback && ensureCallback();
                    }}
                >
                    <Text style={{fontSize: theme.setSpText(38), color: '#3382C7'}}>确定</Text>
                </TouchableOpacity>
              </View>
            }
          </Animated.View>
        </Modal>
      </View>
    );
  }

  _close() {
    this.onRequestClose();
  }

  ensureCallback() {
    this.props.navigation.goBack(null);
  }

}

Popover.propTypes = {
  hasCancelBtn: PropTypes.bool,      // 是否保留“取消”按钮
  onlyInChose: PropTypes.bool,       // 是否应用在发布说说时
  cancelCallback: PropTypes.func,    // 点击取消后的回调
  ensureCallback: PropTypes.func,    // 点击确定后的回调
  wordsCallback: PropTypes.func,     // 点击发布说说回调
  albumCallback: PropTypes.func,     // 选取相册回调
  takePicsCallback: PropTypes.func,  // 拍摄照片回调
  title: PropTypes.string,           // 提示标题
  content: PropTypes.string,         // 提示内容文字
  useAnimation: PropTypes.bool,      // 是否应用动画
  hasWordBtn: PropTypes.bool         // 是否包含说说
}
Popover.defaultProps = {
  hasCancelBtn: true,
  title: '未定义标题',
  content: '未定义内容',
  onlyInChose: false,
  useAnimation: false,
  hasWordBtn: true
}

const styles = StyleSheet.create({
  modalContainer: {
    position: 'absolute',
    width: screenWidth,
    zIndex: -1,
    height: Platform.OS == 'android' ? screenHeight - StatusBar.currentHeight : screenHeight - 20,
  },
  outerContainer: {
    position: 'absolute',
    width: screenWidth,
    height: screenHeight,
    backgroundColor: 'rgba(1, 1, 1, 0.5)'
  },
  container: {
    width: theme.scaleSize(660),
    backgroundColor: '#fff',
    borderRadius: 8,
    justifyContent: 'center',
    alignItems: 'center',
    position: 'absolute',
    top: theme.scaleSize(410),
    left: (screenWidth - theme.scaleSize(660)) / 2,
  },
  promptContainer: {
    width: theme.scaleSize(660),
    alignItems: 'center',
  },
  choseContainer:{

  },
  choseItem:{
    height: theme.scaleSize(120),
    width: theme.scaleSize(660),
    paddingHorizontal: theme.scaleSize(160),
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    borderBottomWidth: segment.width,
    borderBottomColor: '#999999',
  },
  titleContainer:{
    width: theme.scaleSize(660),
    height: theme.scaleSize(116),
    borderBottomColor: '#F2F2F2',
    borderBottomWidth: segment.width,
    justifyContent: 'center',
    alignItems: 'center'
  },
  contentContainer:{
    width: theme.scaleSize(660),
    height: theme.scaleSize(246),
    padding:theme.scaleSize(40),
    // justifyContent: 'center',
    alignItems: 'center'
  },
  buttonContainer: {
    height: theme.scaleSize(100),
    width: theme.scaleSize(660),
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    borderTopWidth: segment.width,
    borderColor: '#999999'
  },
  center: {
    alignItems: 'center',
    justifyContent: 'center',
  },
  line: {
    height: theme.scaleSize(100),
    width: segment.width,
    backgroundColor: '#999999'
  }
});


效果图:
1212121212.gif

相关文章

网友评论

      本文标题:react native 弹框设计,兼容IOS和Android

      本文链接:https://www.haomeiwen.com/subject/qxfhtxtx.html