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 (
this.onRequestClose()}>
this.onRequestClose()}
>
{
this.props.onlyInChose ?
拍摄照片
相册选择
{
hasWordBtn &&
文字说说
}
:
{title}
{content}
}
{
this.props.onlyInChose ?
null
:
{
hasCancelBtn &&
{
this._close();
// 取消后的事件
cancelCallback && cancelCallback()
}}
>
取消
}
{
this.onRequestClose();
// 子组件传递数据到父组件
ensureCallback && ensureCallback();
}}
>
确定
}
);
}
_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'
}
});