react native仿微信PopupWindow效果

来源:互联网 发布:cnc模拟仿真软件 编辑:程序博客网 时间:2024/06/01 23:27

在原生APP开发中,相信很多开发者都会见到这种场景:点击右上角更多的选项,弹出一个更多界面供用户选择。这种控件在原生开发中Android可以用PopupWindow实现,在iOS中可以用CMPopTipView,也可以自己写一个View实现。其类似的效果如下图所示: 
这里写图片描述

实现思路分析: 
要实现上面的视图,有很多种实现方式。前面的文章说过,要实现弹框相关的可以用React Native 提供的 Modal组件(Modal组件),使用Modal组件可以实现我们原生开发中的大多数效果。 
要实现下拉三角,可以让美工切一个带下拉三角的背景,当然也可以自己通过ART实现(ART绘制)。对于选项卡的内容,在原生开发中为了适应更多的场景,我们一般会选择使用ListView组件,然后当点击某个Item的时候获得相应的属性即可。为了控制Modal的显示与消失,我们可以给Modal内置一个isVisible: this.props.show状态。

源码

要实现上面的效果,会这涉及到三个js文件:MorePopWidows.js、Utils.js、HomeActionBar.js,按照先后顺序,代码如下: 
Utils.js

import {Dimensions} from 'react-native'const deviceH = Dimensions.get('window').heightconst deviceW = Dimensions.get('window').widthconst basePx = 375export default function px2dp(px) {    return px *  deviceW / basePx}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

MorePopWidows.js

import React from 'react'import {    StyleSheet,    Platform,    View,    Text,    Image,    TouchableOpacity,    Alert,    Modal,    Dimensions,} from 'react-native'import SpacingView from "./SpacingView";import QRScanPage from "../home/QRScanPage";const { width, height } = Dimensions.get('window');import px2dp from '../util/Utils'const mTop = px2dp(Platform.OS == "ios" ? 64 : 44)let mwidth = 95;let mheight = 100;const marginTop = mTop;export default class MorePopWidows extends React.Component {    constructor(props) {        super(props);        this.state = {            isVisible: this.props.show,        }        mwidth = this.props.width ;        mheight = this.props.height ;    }    componentWillReceiveProps(nextProps) {        this.setState({ isVisible: nextProps.show });    }    closeModal() {        this.setState({            isVisible: false        });        this.props.closeModal(false);    }    scan() {        this.props.navigator.push({            component: QRScanPage,        })    }    render() {        return (            <View style={styles.container}>              <Modal                  transparent={true}                  visible={this.state.isVisible}                  animationType={'fade'}                  onRequestClose={() => this.closeModal()}>                <TouchableOpacity style={styles.container} activeOpacity={1} onPress={() => this.closeModal()}>                  <View style={styles.modal}>                    <TouchableOpacity activeOpacity={1} onPress={this.scan.bind(this)} style={styles.itemView}>                      <Image style={styles.imgStyle} source={require('../images/ic_scan_code_white.png')} />                      <Text style={styles.textStyle}>扫一扫</Text>                    </TouchableOpacity>                     <SpacingView/>                    <TouchableOpacity activeOpacity={1} onPress={() => Alert.alert('点击了付款码')} style={styles.itemView}>                      <Image style={styles.imgStyle} source={require('../images/ic_code_white.png')} />                      <Text style={styles.textStyle}>付款码</Text>                    </TouchableOpacity>                  </View>                </TouchableOpacity>              </Modal>            </View>        )    }}const styles = StyleSheet.create({    container: {        width: width,        height: height,    },    modal: {        backgroundColor: '#696969',        width: mwidth,        height: mheight,        position: 'absolute',        left: width - mwidth - 10,        top: marginTop,        padding: 5,        justifyContent: 'center',        alignItems: 'center',        borderRadius: 3,    },    itemView: {        flexDirection: 'row',        justifyContent: 'center',        alignItems: 'center',        flex: 1,    },    textStyle: {        color: '#fff',        fontSize: 14,        marginLeft: 2,    },    imgStyle: {        width: 20,        height: 20,    }});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

最后是在代码中使用MorePopWidows的代码: 
HomeActionBar.js

/** * https://github.com/facebook/react-native * @flow 首页的标题栏 */import React, {Component} from 'react';import {Platform, View, Dimensions, Text, StyleSheet, TouchableOpacity, Image} from 'react-native';import SelectCityPage from '../home/SelectCityPage'import MorePopWidows from '../component/MorePopWidows'import px2dp from '../util/Utils'const isIOS = Platform.OS == "ios"const {width, height} = Dimensions.get('window')const headH = px2dp(isIOS ? 64 : 44)export default  class HomeActionBar extends Component {    constructor(props) {        super(props);        this.state = {            showPop: false,        }    }    city() {        this.props.navigator.push({            component: SelectCityPage,        })    }    renderHeader() {        return (            <View >            <View style={styles.headerStyle}>                <TouchableOpacity style={styles.action} onPress={this.city.bind(this)}>                    <Text style={styles.text}>上海</Text>                    <Image                        source={require('../images/ic_arrow_down.png')}/>                </TouchableOpacity>                <TouchableOpacity style={styles.searchBar}>                    <Image source={require('../images/ic_search.png')} style={styles.iconStyle}/>                    <Text style={{fontSize: 13, color: "#666", marginLeft: 5}}>输入商家、商品名称</Text>                </TouchableOpacity>                <TouchableOpacity style={styles.action} onPress={() => { this.setState({ showPop: !this.state.showPop }) }}>                    <Image style={styles.scanIcon}                           source={require('../images/ic_scan_code_white.png')}/>                    <Text style={styles.scanText}>扫码</Text>                </TouchableOpacity>            </View>                <View style={{ position: 'absolute', top: headH, left: 0, width: width, height: height }}>                    <MorePopWidows width={90} height={100} show={this.state.showPop} closeModal={(show) => {                        this.setState({showPop: show})                    }} {...this.props}/>                </View>            </View>        )    }    render() {        return (            <View>                {this.renderHeader()}            </View>        );    }}const styles = StyleSheet.create({    headerStyle: {        backgroundColor: "#06C1AE",        height: headH,        paddingTop: px2dp(isIOS ? 20 : 0),        paddingHorizontal: 16,        flexDirection: 'row',        alignItems: 'center',    },    searchBar: {        width: width * 0.65,        height: 30,        borderRadius: 19,        marginLeft: 10,        flexDirection: 'row',        justifyContent: 'flex-start',        alignItems: 'center',        backgroundColor: 'white',        alignSelf: 'center',        paddingLeft: 10,    },    text: {        fontSize: 16,        color: '#ffffff',        justifyContent: 'center',    },    iconStyle: {        width: 22,        height: 22,    },    action: {        flexDirection: 'row',        justifyContent: 'center',        alignItems: 'center',    },    scanIcon: {        width: 28,        height: 28,        alignItems: 'center',        marginLeft: 10,    },    scanText: {        fontSize: 14,        color: '#ffffff',        justifyContent: 'center',        alignItems: 'center',    },});
原创粉丝点击