前序
无论在web端还是原生Native应用,弹窗使用场景都随处可见,弹窗UI设计的好坏很大程度上直接决定用户体验。如微信、支付宝的弹窗交互就操作方便、使用舒适。
说明
很早之前就有使用h5开发过手机端弹窗,最近一直在捣鼓react-native技术,踩了不少坑。就想着用react-native技术做个自定义Modal弹窗来实践一把。
rnPop是一个基于React/React-Native技术开发的高自定义弹窗组件,仿制了android、ios、微信弹窗效果。结合了原生Modal及react能力,使得弹窗高度自定义化,调用优雅、简洁、方便。
预览效果图
目录结构
弹窗引入及调用
参考了很多别人自定义react-native弹窗调用方式,无非就是下面这样
// 引入rnPop.js组件
import RNPop from '../utils/rnPop/rnPop.js'
render() {
return (
...
{/* 引入弹窗模板 */}
)
}
显示:this.refs.rnPop.show({...options});
隐藏:this.refs.rnPop.hide();
这种调用方式是可以访问组件内部方法,如show、hide方法,可总感觉代码不够优雅,而且不能全局调用。
改进
在弹窗内部定义两个静态方法
/**************************
* 显示弹窗事件(处理传参)
*/
static show = (args) => {
_this.setState({
..._this.props, ...args, isVisible: true
}, _this.in)
}
/**************************
* 关闭弹窗事件
*/
static close = () => {
_this.out()
}
通过react-native全局变量global,对外提供全局调用接口rnPop
/**************************
* 实例化弹窗接口
*/
const Popup = (args) => {
RNPop.show(args)
}
Popup.close = () => {
RNPop.close()
}
global.rnPop = Popup
这样就可以非常优雅的使用rnPop({...options}) 、 rnPop.close()方式进行弹窗调用了。
//msg提示
handlePress01 = ()=> {
rnPop({
content: 'msg消息提示框(5s后窗口关闭)',
shade: true,
shadeClose: false,
time: 5,
xtime: true,
anim: 'fadeIn',
});
}
//msg提示(黑色背景)
handlePress02 = ()=> {
rnPop({
content: '自定义弹窗背景',
shade: false,
style: {backgroundColor: 'rgba(17,17,17,.7)', borderRadius: 6},
contentStyle: {color: '#fff', padding: 10},
time: 2
});
}
RN自定义Toast
react-native自定义toast支持四种图标 success/info/error/loading
//Toast演示
handlePress15 = ()=> {
rnPop({
skin: 'toast',
content: '操作成功',
icon: 'success', //success | info | error | loading
shade: false,
time: 3
});
}
ios弹窗效果
//ios对话框
handlePress16 = ()=> {
rnPop({
skin: 'footer',
content: 'Apple ID \n [email protected]',
shadeClose: false,
anim: 'bottom',
btns: [
{
text: '注销账号',
style: {color: '#30a4fc'},
onPress() {
console.log('您点击了恢复!');
}
},
{
text: '删除',
style: {color: '#e63d23'},
onPress() {
console.log('您点击了删除!');
//删除回调提示
rnPop({
anim: 'fadeIn',
content: '您点击了删除功能',
shade: true,
time: 3
});
}
},
{
text: '取消',
style: {color: '#999'},
onPress() {
console.log('您点击了取消!');
rnPop.close();
}
}
]
});
}
android及仿微信效果
// android 样式
handlePress20 = ()=>{
rnPop({
skin: 'android',
title: '发现新版本',
content: '程序员GG紧急修复了一个闪退bug,给您带来的不便敬请谅解。\n\n[近期更新]\n 1、新增资讯&话题入口 \n 2、新增详情页面长按分享功能',
shadeClose: false,
btns: [
{
text: '知道了',
onPress() {
rnPop.close();
console.log("知道了");
}
},
{
text: '更新',
style: {color: '#4eca33'},
onPress() {
console.log('您点击了更新!');
}
}
]
});
}
自定义弹窗模板
还支持对传入content参数进行自定义模板 content: string | object
// 自定义调用
handlePressAA = () => {
rnPop({
content: (
//
//
// 长按或扫一扫二维码,加我好友
// 保存二维码
//
),
anim: 'bottom'
});
}
// 自定义模板
const DefineCp = () => {
return (
长按或扫一扫二维码,加我好友
保存二维码
)
}
参数配置
/**
* @Title react-native弹窗插件 rnPop-v1.0 beta (UTF-8)
* @Create 2019/08/01 10:00:50 GMT+0800 (中国标准时间)
* @Author andy Q:282310962 wx:xy190310
*/
'use strict'
import React, {Component} from 'react'
import {
Animated, Easing, StyleSheet, Dimensions, PixelRatio, TouchableHighlight, Modal, View, Text, Image, ActivityIndicator
} from 'react-native'
const pixel = PixelRatio.get()
const {width, height} = Dimensions.get('window')
export default class RNPop extends Component{
/**************************
* 弹窗配置参数
*/
static defaultProps = {
isVisible: false, //弹窗显示
title: '', //标题
content: '', //内容
style: null, //自定义弹窗样式 {object}
contentStyle: null, //内容样式
skin: '', //自定义弹窗风格
icon: '', //自定义弹窗图标
shade: true, //遮罩层
shadeClose: true, //点击遮罩层关闭
opacity: '', //遮罩层透明度
time: 0, //弹窗自动关闭秒数
xtime: false, //显示关闭秒数
anim: 'scaleIn', //弹窗动画(scaleIn / fadeIn / top / bottom / left / right)
follow: null, //跟随定位(适用于在长按位置定位弹窗)
position: '', //弹窗位置
btns: null, //弹窗按钮(不设置则不显示按钮)[{...options}, {...options}]
}
constructor(props){
super(props)
this.state = {
...this.props,
animatedValue: new Animated.Value(0),
}
this.timer = null
}
render(){
let opt = this.state
// __自定义toast图标
let slotImg = {
success: require('./skin/success.png'),
error: require('./skin/error.png'),
info: require('./skin/info.png'),
}
return (
...
)
}
// 执行动画
in = () => {
Animated.timing(
this.state.animatedValue, {easing: Easing.linear, duration: 300, toValue: 1}
).start()
}
out = () => {
Animated.timing(
this.state.animatedValue, {easing: Easing.linear, duration: 100, toValue: 0}
).start(()=>{
this.setState({
...this.props
})
})
this.timer && clearTimeout(this.timer)
delete this.timer
}
/**************************
* 显示弹窗事件(处理传参)
*/
static show = (args) => {
_this.setState({
..._this.props, ...args, isVisible: true
}, _this.in)
}
/**************************
* 关闭弹窗事件
*/
static close = () => {
_this.out()
}
}
更多
附上之前的h5移动端和微信小程序弹窗
h5手机端弹窗:https://www.cnblogs.com/xiaoy...
h5网页版弹窗:https://www.cnblogs.com/xiaoy...
wx小程序弹窗:https://www.cnblogs.com/xiaoy...