Toast
在common文件夹下新建Toast文件夹,把这里面的两个文件放进去(Toast ) Toast.js
'use strict' ;
import React, { Component } from 'react' ;
import { View } from 'react-native' ;
import Overlay from '../Overlay/Overlay' ;
import ToastView from './ToastView' ;
export default class Toast extends Overlay {
static ToastView = ToastView;
static defaultDuration = 'short' ;
static defaultPosition = 'center' ;
static messageDefaultDuration = 'short' ;
static messageDefaultPosition = 'bottom' ;
static show ( options) {
let { duration, ... others } =
options && typeof options === 'object' ? options : { } ;
let key = super . show ( < this . ToastView { ... others} / > ) ;
if ( typeof duration !== 'number' ) {
switch ( duration) {
case 'long' :
duration = 3500 ;
break ;
default :
duration = 2000 ;
break ;
}
}
setTimeout ( ( ) => this . hide ( key) , duration) ;
return key;
}
static message (
text,
duration = this . messageDefaultDuration,
position = this . messageDefaultPosition,
) {
return this . show ( { text, duration, position } ) ;
}
static success (
text,
duration = this . defaultDuration,
position = this . defaultPosition,
) {
return this . show ( { text, duration, position, icon: 'success' } ) ;
}
static fail (
text,
duration = this . defaultDuration,
position = this . defaultPosition,
) {
return this . show ( { text, duration, position, icon: 'fail' } ) ;
}
static smile (
text,
duration = this . defaultDuration,
position = this . defaultPosition,
) {
return this . show ( { text, duration, position, icon: 'smile' } ) ;
}
static sad (
text,
duration = this . defaultDuration,
position = this . defaultPosition,
) {
return this . show ( { text, duration, position, icon: 'sad' } ) ;
}
static info (
text,
duration = this . defaultDuration,
position = this . defaultPosition,
) {
return this . show ( { text, duration, position, icon: 'info' } ) ;
}
static stop (
text,
duration = this . defaultDuration,
position = this . defaultPosition,
) {
return this . show ( { text, duration, position, icon: 'stop' } ) ;
}
}
ToastView.js
'use strict' ;
import React from 'react' ;
import PropTypes from 'prop-types' ;
import { View, Image, Text } from 'react-native' ;
import Theme from '../../../themes/Theme' ;
import Overlay from '../Overlay/Overlay' ;
export default class ToastView extends Overlay. View {
static propTypes = {
... Overlay. View. propTypes,
text: PropTypes. oneOfType ( [
PropTypes. element,
PropTypes. string,
PropTypes. number,
] ) ,
icon: PropTypes. oneOfType ( [
PropTypes. element,
PropTypes. shape ( { uri: PropTypes. string } ) ,
PropTypes. number,
PropTypes. oneOf ( [
'none' ,
'success' ,
'fail' ,
'smile' ,
'sad' ,
'info' ,
'stop' ,
] ) ,
] ) ,
position: PropTypes. oneOf ( [ 'top' , 'bottom' , 'center' ] ) ,
} ;
static defaultProps = {
... Overlay. View. defaultProps,
overlayOpacity: 0 ,
overlayPointerEvents: 'none' ,
closeOnHardwareBackPress: false ,
position: 'center' ,
} ;
get overlayPointerEvents ( ) {
let { overlayPointerEvents, modal } = this . props;
return modal ? 'auto' : overlayPointerEvents;
}
buildStyle ( ) {
let { style, position } = this . props;
style = [
{
paddingLeft: Theme. toastScreenPaddingLeft,
paddingRight: Theme. toastScreenPaddingRight,
paddingTop: Theme. toastScreenPaddingTop,
paddingBottom: Theme. toastScreenPaddingBottom,
justifyContent:
position === 'top'
? 'flex-start'
: position === 'bottom'
? 'flex-end'
: 'center' ,
alignItems: 'center' ,
} ,
] . concat ( super . buildStyle ( ) ) ;
return style;
}
renderIcon ( ) {
let { icon } = this . props;
if ( ! icon && icon !== 0 ) {
return null ;
}
let image;
if ( ! React. isValidElement ( icon) ) {
let imageSource;
if ( typeof icon === 'string' ) {
switch ( icon) {
case 'success' :
imageSource = require ( '../../../asserts/icons/success.png' ) ;
break ;
case 'fail' :
imageSource = require ( '../../../asserts/icons/fail.png' ) ;
break ;
case 'smile' :
imageSource = require ( '../../../asserts/icons/smile.png' ) ;
break ;
case 'sad' :
imageSource = require ( '../../../asserts/icons/sad.png' ) ;
break ;
case 'info' :
imageSource = require ( '../../../asserts/icons/info.png' ) ;
break ;
case 'stop' :
imageSource = require ( '../../../asserts/icons/stop.png' ) ;
break ;
default :
imageSource = null ;
break ;
}
} else {
imageSource = icon;
}
image = (
< Image
style= { {
width: Theme. toastIconWidth,
height: Theme. toastIconHeight,
tintColor: Theme. toastIconTintColor,
} }
source= { imageSource}
/ >
) ;
} else {
image = icon;
}
return (
< View
style= { {
paddingTop: Theme. toastIconPaddingTop,
paddingBottom: Theme. toastIconPaddingBottom,
} }
>
{ image}
< / View>
) ;
}
renderText ( ) {
let { text } = this . props;
if ( typeof text === 'string' || typeof text === 'number' ) {
text = (
< Text
style= { { color: Theme. toastTextColor, fontSize: Theme. toastFontSize } }
>
{ text}
< / Text>
) ;
}
return text;
}
renderContent ( ) {
let contentStyle = {
backgroundColor: Theme. toastColor,
paddingLeft: Theme. toastPaddingLeft,
paddingRight: Theme. toastPaddingRight,
paddingTop: Theme. toastPaddingTop,
paddingBottom: Theme. toastPaddingBottom,
borderRadius: Theme. toastBorderRadius,
alignItems: 'center' ,
} ;
return (
< View style= { contentStyle} >
{ this . renderIcon ( ) }
{ this . renderText ( ) }
< / View>
) ;
}
}
Overlay
因为Toast需要Overlay,所以还得把Overlay 也引入 在common文件夹下新建文件夹Overlay Overlay.js
'use strict' ;
import React, { Component } from 'react' ;
import { View } from 'react-native' ;
import TopView from './TopView' ;
import OverlayView from './OverlayView' ;
import OverlayPullView from './OverlayPullView' ;
import OverlayPopView from './OverlayPopView' ;
import OverlayPopoverView from './OverlayPopoverView' ;
export default class Overlay {
static View = OverlayView;
static PullView = OverlayPullView;
static PopView = OverlayPopView;
static PopoverView = OverlayPopoverView;
static show ( overlayView) {
let key;
let onDisappearCompletedSave = overlayView. props. onDisappearCompleted;
let element = React. cloneElement ( overlayView, {
onDisappearCompleted: ( ) => {
TopView. remove ( key) ;
onDisappearCompletedSave && onDisappearCompletedSave ( ) ;
} ,
} ) ;
key = TopView. add ( element) ;
return key;
}
static hide ( key) {
TopView. remove ( key) ;
}
static transformRoot ( transform, animated, animatesOnly = null ) {
TopView. transform ( transform, animated, animatesOnly) ;
}
static restoreRoot ( animated, animatesOnly = null ) {
TopView. restore ( animated, animatesOnly) ;
}
}
'use strict' ;
import React, { Component } from 'react' ;
import PropTypes from 'prop-types' ;
import { View, Dimensions, Platform, StatusBar } from 'react-native' ;
import OverlayView from './OverlayView' ;
import Popover from '../Popover/Popover' ;
export default class OverlayPopoverView extends OverlayView {
static propTypes = {
... OverlayView. propTypes,
popoverStyle: Popover. propTypes. style,
fromBounds: PropTypes. shape ( {
x: PropTypes. number. isRequired,
y: PropTypes. number. isRequired,
width: PropTypes. number,
height: PropTypes. number,
} ) . isRequired,
direction: PropTypes. oneOf ( [ 'down' , 'up' , 'right' , 'left' ] ) ,
autoDirection: PropTypes. bool,
directionInsets: PropTypes. number,
align: PropTypes. oneOf ( [ 'start' , 'center' , 'end' ] ) ,
alignInsets: PropTypes. number,
showArrow: PropTypes. bool,
paddingCorner: Popover. propTypes. paddingCorner,
} ;
static defaultProps = {
... OverlayView. defaultProps,
overlayOpacity: 0 ,
direction: 'down' ,
autoDirection: true ,
align: 'end' ,
showArrow: true ,
} ;
constructor ( props) {
super ( props) ;
Object. assign ( this . state, {
fromBounds: props. fromBounds,
popoverWidth: null ,
popoverHeight: null ,
} ) ;
this . defaultDirectionInsets = 0 ;
}
componentDidUpdate ( prevProps, prevState, snapshot) {
super . componentDidUpdate &&
super . componentDidUpdate ( prevProps, prevState, snapshot) ;
if (
JSON . stringify ( this . props. fromBounds) !==
JSON . stringify ( this . state. fromBounds)
) {
this . setState ( { fromBounds: this . props. fromBounds } ) ;
}
}
updateFromBounds ( bounds) {
this . setState ( { fromBounds: bounds } ) ;
}
onPopoverLayout ( e) {
if (
Platform. OS === 'android' &&
( this . state. popoverWidth !== null || this . state. popoverHeight != null )
) {
return ;
}
let { width, height } = e. nativeEvent. layout;
if (
width !== this . state. popoverWidth ||
height !== this . state. popoverHeight
) {
this . setState ( { popoverWidth: width, popoverHeight: height } ) ;
}
}
buildPopoverStyle ( ) {
let { fromBounds, popoverWidth, popoverHeight } = this . state;
let {
popoverStyle,
direction,
autoDirection,
directionInsets,
align,
alignInsets,
showArrow,
arrow,
} = this . props;
if ( popoverWidth === null || popoverHeight === null ) {
popoverStyle = [ ]
. concat ( popoverStyle)
. concat ( { position: 'absolute' , left: 0 , top: 0 , opacity: 0 } ) ;
if ( ! showArrow) {
arrow = 'none' ;
} else {
switch ( direction) {
case 'right' :
arrow = 'left' ;
break ;
case 'left' :
arrow = 'right' ;
break ;
case 'up' :
arrow = 'bottom' ;
break ;
default :
arrow = 'top' ;
break ;
}
}
return { popoverStyle, arrow } ;
}
let screenWidth = Dimensions. get ( 'window' ) . width;
let screenHeight = Dimensions. get ( 'window' ) . height;
let { x, y, width, height } = fromBounds ? fromBounds : { } ;
if ( ! x && x !== 0 ) {
x = screenWidth / 2 ;
}
if ( ! y && y !== 0 ) {
y = screenHeight / 2 ;
}
if ( ! width) {
width = 0 ;
}
if ( ! height) {
height = 0 ;
}
if ( ! directionInsets && directionInsets !== 0 ) {
directionInsets = this . defaultDirectionInsets;
}
if ( ! alignInsets) {
alignInsets = 0 ;
}
let ph = popoverHeight + directionInsets;
let pw = popoverWidth + directionInsets;
switch ( direction) {
case 'right' :
if ( autoDirection && x + width + pw > screenWidth && x >= pw) {
direction = 'left' ;
}
break ;
case 'left' :
if ( autoDirection && x + width + pw <= screenWidth && x < pw) {
direction = 'right' ;
}
break ;
case 'up' :
if ( autoDirection && y + height + ph <= screenHeight && y < ph) {
direction = 'down' ;
}
break ;
default :
if ( autoDirection && y + height + ph > screenHeight && y >= ph) {
direction = 'up' ;
}
break ;
}
let px, py;
switch ( direction) {
case 'right' :
px = x + width + directionInsets;
arrow = 'left' ;
break ;
case 'left' :
px = x - popoverWidth - directionInsets;
arrow = 'right' ;
break ;
case 'up' :
py = y - popoverHeight - directionInsets;
arrow = 'bottom' ;
break ;
default :
py = y + height + directionInsets;
arrow = 'top' ;
break ;
}
if ( direction == 'down' || direction == 'up' ) {
switch ( align) {
case 'start' :
px = x - alignInsets;
arrow += 'Left' ;
break ;
case 'center' :
px = x + width / 2 - popoverWidth / 2 ;
break ;
default :
px = x + width - popoverWidth + alignInsets;
arrow += 'Right' ;
break ;
}
} else if ( direction == 'right' || direction == 'left' ) {
switch ( align) {
case 'end' :
py = y + height - popoverHeight + alignInsets;
arrow += 'Bottom' ;
break ;
case 'center' :
py = y + height / 2 - popoverHeight / 2 ;
break ;
default :
py = y - alignInsets;
arrow += 'Top' ;
break ;
}
}
popoverStyle = [ ] . concat ( popoverStyle) . concat ( {
position: 'absolute' ,
left: px,
top: py,
} ) ;
if ( ! showArrow) {
arrow = 'none' ;
}
return { popoverStyle, arrow } ;
}
renderContent ( content = null ) {
let { paddingCorner, children } = this . props;
let { popoverStyle, arrow } = this . buildPopoverStyle ( ) ;
return (
< Popover
style= { popoverStyle}
arrow= { arrow}
paddingCorner= { paddingCorner}
onLayout= { ( e) => this . onPopoverLayout ( e) }
>
{ content ? content : children}
< / Popover>
) ;
}
}
'use strict' ;
import React, { Component } from 'react' ;
import PropTypes from 'prop-types' ;
import { Animated, View, ViewPropTypes } from 'react-native' ;
import OverlayView from './OverlayView' ;
export default class OverlayPopView extends OverlayView {
static propTypes = {
... OverlayView. propTypes,
type: PropTypes. oneOf ( [ 'zoomOut' , 'zoomIn' , 'custom' ] ) ,
containerStyle: ViewPropTypes. style,
customBounds: PropTypes. shape ( {
x: PropTypes. number. isRequired,
y: PropTypes. number. isRequired,
width: PropTypes. number. isRequired,
height: PropTypes. number. isRequired,
} ) ,
} ;
static defaultProps = {
... OverlayView. defaultProps,
type: 'zoomOut' ,
animated: true ,
} ;
constructor ( props) {
super ( props) ;
this . viewLayout = { x: 0 , y: 0 , width: 0 , height: 0 } ;
Object. assign ( this . state, {
opacity: new Animated. Value ( 1 ) ,
translateX: new Animated. Value ( 0 ) ,
translateY: new Animated. Value ( 0 ) ,
scaleX: new Animated. Value ( 1 ) ,
scaleY: new Animated. Value ( 1 ) ,
showed: false ,
} ) ;
}
get appearAnimates ( ) {
let animates = super . appearAnimates;
let duration = 200 ;
animates = animates. concat ( [
Animated. timing ( this . state. opacity, {
toValue: 1 ,
duration,
useNativeDriver: false ,
} ) ,
Animated. timing ( this . state. translateX, {
toValue: 0 ,
duration,
useNativeDriver: false ,
} ) ,
Animated. timing ( this . state. translateY, {
toValue: 0 ,
duration,
useNativeDriver: false ,
} ) ,
Animated. timing ( this . state. scaleX, {
toValue: 1 ,
duration,
useNativeDriver: false ,
} ) ,
Animated. timing ( this . state. scaleY, {
toValue: 1 ,
duration,
useNativeDriver: false ,
} ) ,
] ) ;
return animates;
}
get disappearAnimates ( ) {
let animates = super . disappearAnimates;
let duration = 200 ;
let ft = this . fromTransform;
animates = animates. concat ( [
Animated. timing ( this . state. opacity, {
toValue: 0 ,
duration,
useNativeDriver: false ,
} ) ,
Animated. timing ( this . state. translateX, {
toValue: ft. translateX,
duration,
useNativeDriver: false ,
} ) ,
Animated. timing ( this . state. translateY, {
toValue: ft. translateY,
duration,
useNativeDriver: false ,
} ) ,
Animated. timing ( this . state. scaleX, {
toValue: ft. scaleX,
duration,
useNativeDriver: false ,
} ) ,
Animated. timing ( this . state. scaleY, {
toValue: ft. scaleY,
duration,
useNativeDriver: false ,
} ) ,
] ) ;
return animates;
}
get appearAfterMount ( ) {
return false ;
}
get fromBounds ( ) {
let { type, customBounds } = this . props;
let bounds;
if ( type === 'custom' && ! customBounds) {
console. error (
'OverlayPopView: customBounds can not be null when type is "custom"' ,
) ;
}
if ( type === 'custom' && customBounds) {
bounds = customBounds;
} else {
let zoomRate = type === 'zoomIn' ? 0.3 : 1.2 ;
let { x, y, width, height } = this . viewLayout;
bounds = {
x: x - ( width * zoomRate - width) / 2 ,
y: y - ( height * zoomRate - height) / 2 ,
width: width * zoomRate,
height: height * zoomRate,
} ;
}
return bounds;
}
get fromTransform ( ) {
let fb = this . fromBounds;
let tb = this . viewLayout;
let transform = {
translateX: fb. x + fb. width / 2 - ( tb. x + tb. width / 2 ) ,
translateY: fb. y + fb. height / 2 - ( tb. y + tb. height / 2 ) ,
scaleX: fb. width / tb. width,
scaleY: fb. height / tb. height,
} ;
return transform;
}
appear ( animated = this . props. animated) {
if ( animated) {
let { opacity, translateX, translateY, scaleX, scaleY } = this . state;
let ft = this . fromTransform;
opacity. setValue ( 0 ) ;
translateX. setValue ( ft. translateX) ;
translateY. setValue ( ft. translateY) ;
scaleX. setValue ( ft. scaleX) ;
scaleY. setValue ( ft. scaleY) ;
}
super . appear ( animated) ;
}
onLayout ( e) {
this . viewLayout = e. nativeEvent. layout;
if ( ! this . state. showed) {
this . setState ( { showed: true } ) ;
this . appear ( ) ;
}
}
renderContent ( content = null ) {
let { containerStyle, children } = this . props;
let { opacity, translateX, translateY, scaleX, scaleY } = this . state;
containerStyle = [
{
backgroundColor: 'rgba(0, 0, 0, 0)' ,
minWidth: 1 ,
minHeight: 1 ,
} ,
]
. concat ( containerStyle)
. concat ( {
opacity: this . state. showed ? opacity : 0 ,
transform: [ { translateX } , { translateY } , { scaleX } , { scaleY } ] ,
} ) ;
return (
< Animated. View
style= { containerStyle}
pointerEvents= "box-none"
onLayout= { ( e) => this . onLayout ( e) }
>
{ content ? content : children}
< / Animated. View>
) ;
}
}
'use strict' ;
import React, { Component } from 'react' ;
import PropTypes from 'prop-types' ;
import { Animated, View, ViewPropTypes } from 'react-native' ;
import Theme from '../../../themes/Theme' ;
import TopView from './TopView' ;
import OverlayView from './OverlayView' ;
export default class OverlayPullView extends OverlayView {
static propTypes = {
... OverlayView. propTypes,
side: PropTypes. oneOf ( [ 'top' , 'bottom' , 'left' , 'right' ] ) ,
containerStyle: ViewPropTypes. style,
rootTransform: PropTypes. oneOfType ( [
PropTypes. oneOf ( [ 'none' , 'translate' , 'scale' ] ) ,
PropTypes. arrayOf (
PropTypes. shape ( {
translateX: PropTypes. number,
translateY: PropTypes. number,
scaleX: PropTypes. number,
scaleY: PropTypes. number,
} ) ,
) ,
] ) ,
} ;
static defaultProps = {
... OverlayView. defaultProps,
side: 'bottom' ,
animated: true ,
rootTransform: 'none' ,
} ;
constructor ( props) {
super ( props) ;
this . viewLayout = { x: 0 , y: 0 , width: 0 , height: 0 } ;
Object. assign ( this . state, {
marginValue: new Animated. Value ( 0 ) ,
showed: false ,
} ) ;
}
get appearAnimates ( ) {
let animates = super . appearAnimates;
animates. push (
Animated. spring ( this . state. marginValue, {
toValue: 0 ,
friction: 9 ,
useNativeDriver: false ,
} ) ,
) ;
return animates;
}
get disappearAnimates ( ) {
let animates = super . disappearAnimates;
animates. push (
Animated. spring ( this . state. marginValue, {
toValue: this . marginSize,
friction: 9 ,
useNativeDriver: false ,
} ) ,
) ;
return animates;
}
get appearAfterMount ( ) {
return false ;
}
get marginSize ( ) {
let { side } = this . props;
if ( side === 'left' || side === 'right' ) {
return - this . viewLayout. width;
} else {
return - this . viewLayout. height;
}
}
get rootTransformValue ( ) {
let { side, rootTransform } = this . props;
if ( ! rootTransform || rootTransform === 'none' ) {
return [ ] ;
}
let transform;
switch ( rootTransform) {
case 'translate' :
switch ( side) {
case 'top' :
return [ { translateY: this . viewLayout. height } ] ;
case 'left' :
return [ { translateX: this . viewLayout. width } ] ;
case 'right' :
return [ { translateX: - this . viewLayout. width } ] ;
default :
return [ { translateY: - this . viewLayout. height } ] ;
}
break ;
case 'scale' :
return [
{ scaleX: Theme. overlayRootScale } ,
{ scaleY: Theme. overlayRootScale } ,
] ;
default :
return rootTransform;
}
}
appear ( animated = this . props. animated) {
if ( animated) {
this . state. marginValue. setValue ( this . marginSize) ;
}
super . appear ( animated) ;
let { rootTransform } = this . props;
if ( rootTransform && rootTransform !== 'none' ) {
TopView. transform ( this . rootTransformValue, animated) ;
}
}
disappear ( animated = this . props. animated) {
let { rootTransform } = this . props;
if ( rootTransform && rootTransform !== 'none' ) {
TopView. restore ( animated) ;
}
super . disappear ( animated) ;
}
onLayout ( e) {
this . viewLayout = e. nativeEvent. layout;
if ( ! this . state. showed) {
this . setState ( { showed: true } ) ;
this . appear ( ) ;
}
}
buildStyle ( ) {
let { side } = this . props;
let sideStyle;
switch ( side) {
case 'top' :
sideStyle = {
flexDirection: 'column' ,
justifyContent: 'flex-start' ,
alignItems: 'stretch' ,
} ;
break ;
case 'left' :
sideStyle = {
flexDirection: 'row' ,
justifyContent: 'flex-start' ,
alignItems: 'stretch' ,
} ;
break ;
case 'right' :
sideStyle = {
flexDirection: 'row' ,
justifyContent: 'flex-end' ,
alignItems: 'stretch' ,
} ;
break ;
default :
sideStyle = {
flexDirection: 'column' ,
justifyContent: 'flex-end' ,
alignItems: 'stretch' ,
} ;
}
return super . buildStyle ( ) . concat ( sideStyle) ;
}
renderContent ( content = null ) {
let { side, containerStyle, children } = this . props;
let contentStyle;
switch ( side) {
case 'top' :
contentStyle = { marginTop: this . state. marginValue } ;
break ;
case 'left' :
contentStyle = { marginLeft: this . state. marginValue } ;
break ;
case 'right' :
contentStyle = { marginRight: this . state. marginValue } ;
break ;
default :
contentStyle = { marginBottom: this . state. marginValue } ;
}
contentStyle. opacity = this . state. showed ? 1 : 0 ;
containerStyle = [
{
backgroundColor: Theme. defaultColor,
} ,
]
. concat ( containerStyle)
. concat ( contentStyle) ;
return (
< Animated. View style= { containerStyle} onLayout= { ( e) => this . onLayout ( e) } >
{ content ? content : children}
< / Animated. View>
) ;
}
}
'use strict' ;
import React, { Component } from 'react' ;
import PropTypes from 'prop-types' ;
import ReactNative, {
StyleSheet,
Animated,
View,
PanResponder,
Platform,
ViewPropTypes,
} from 'react-native' ;
import Theme from '../../../themes/Theme' ;
import KeyboardSpace from '../KeyboardSpace/KeyboardSpace' ;
export default class OverlayView extends Component {
static propTypes = {
style: ViewPropTypes. style,
modal: PropTypes. bool,
animated: PropTypes. bool,
overlayOpacity: PropTypes. number,
overlayPointerEvents: ViewPropTypes. pointerEvents,
autoKeyboardInsets: PropTypes. bool,
closeOnHardwareBackPress: PropTypes. bool,
onAppearCompleted: PropTypes. func,
onDisappearCompleted: PropTypes. func,
onCloseRequest: PropTypes. func,
} ;
static defaultProps = {
modal: false ,
animated: false ,
overlayPointerEvents: 'auto' ,
autoKeyboardInsets: false ,
closeOnHardwareBackPress: true ,
} ;
constructor ( props) {
super ( props) ;
this . panResponder = PanResponder. create ( {
onStartShouldSetPanResponder: ( e, gestureState) => true ,
onPanResponderGrant: ( e, gestureState) =>
( this . touchStateID = gestureState. stateID) ,
onPanResponderRelease: ( e, gestureState) =>
this . touchStateID == gestureState. stateID ? this . closeRequest ( ) : null ,
} ) ;
this . state = {
overlayOpacity: new Animated. Value ( 0 ) ,
} ;
}
componentDidMount ( ) {
this . appearAfterMount && this . appear ( ) ;
if ( Platform. OS === 'android' ) {
let BackHandler = ReactNative. BackHandler
? ReactNative. BackHandler
: ReactNative. BackAndroid;
this . backListener = BackHandler. addEventListener (
'hardwareBackPress' ,
( ) => {
if ( this . props. closeOnHardwareBackPress) {
this . closeRequest ( ) ;
return true ;
} else {
return false ;
}
} ,
) ;
}
}
componentWillUnmount ( ) {
this . removeBackListener ( ) ;
}
removeBackListener ( ) {
if ( this . backListener) {
this . backListener. remove ( ) ;
this . backListener = null ;
}
}
get overlayOpacity ( ) {
let { overlayOpacity } = this . props;
return overlayOpacity || overlayOpacity === 0
? overlayOpacity
: Theme. overlayOpacity;
}
get appearAnimates ( ) {
let duration = 200 ;
let animates = [
Animated. timing ( this . state. overlayOpacity, {
toValue: this . overlayOpacity,
duration,
useNativeDriver: false ,
} ) ,
] ;
return animates;
}
get disappearAnimates ( ) {
let duration = 200 ;
let animates = [
Animated. timing ( this . state. overlayOpacity, {
toValue: 0 ,
duration,
useNativeDriver: false ,
} ) ,
] ;
return animates;
}
get appearAfterMount ( ) {
return true ;
}
get overlayPointerEvents ( ) {
return this . props. overlayPointerEvents;
}
appear ( animated = this . props. animated, additionAnimates = null ) {
if ( animated) {
this . state. overlayOpacity. setValue ( 0 ) ;
Animated. parallel (
this . appearAnimates. concat ( additionAnimates) ,
) . start ( ( e) => this . appearCompleted ( ) ) ;
} else {
this . state. overlayOpacity. setValue ( this . overlayOpacity) ;
this . appearCompleted ( ) ;
}
}
disappear ( animated = this . props. animated, additionAnimates = null ) {
if ( animated) {
Animated. parallel (
this . disappearAnimates. concat ( additionAnimates) ,
) . start ( ( e) => this . disappearCompleted ( ) ) ;
this . state. overlayOpacity. addListener ( ( e) => {
if ( e. value < 0.01 ) {
this . state. overlayOpacity. stopAnimation ( ) ;
this . state. overlayOpacity. removeAllListeners ( ) ;
}
} ) ;
} else {
this . disappearCompleted ( ) ;
}
}
appearCompleted ( ) {
let { onAppearCompleted } = this . props;
onAppearCompleted && onAppearCompleted ( ) ;
}
disappearCompleted ( ) {
let { onDisappearCompleted } = this . props;
onDisappearCompleted && onDisappearCompleted ( ) ;
}
close ( animated = this . props. animated) {
if ( this . closed) {
return true ;
}
this . closed = true ;
this . removeBackListener ( ) ;
this . disappear ( animated) ;
return true ;
}
closeRequest ( ) {
let { modal, onCloseRequest } = this . props;
if ( onCloseRequest) {
onCloseRequest ( this ) ;
} else if ( ! modal) {
this . close ( ) ;
}
}
buildStyle ( ) {
let { style } = this . props;
style = [ { backgroundColor: 'rgba(0, 0, 0, 0)' , flex: 1 } ] . concat ( style) ;
return style;
}
renderContent ( ) {
return this . props. children;
}
render ( ) {
let { autoKeyboardInsets } = this . props;
return (
< View style= { styles. screen} pointerEvents= { this . overlayPointerEvents} >
< Animated. View
style= { [
styles. screen,
{ backgroundColor: '#000' , opacity: this . state. overlayOpacity } ,
] }
{ ... this . panResponder. panHandlers}
/ >
< View style= { this . buildStyle ( ) } pointerEvents= "box-none" >
{ this . renderContent ( ) }
< / View>
{ autoKeyboardInsets ? < KeyboardSpace / > : null }
< / View>
) ;
}
}
var styles = StyleSheet. create ( {
screen: {
backgroundColor: 'rgba(0, 0, 0, 0)' ,
position: 'absolute' ,
top: 0 ,
left: 0 ,
right: 0 ,
bottom: 0 ,
} ,
} ) ;
'use strict' ;
import React, { Component, PureComponent } from 'react' ;
import {
StyleSheet,
AppRegistry,
DeviceEventEmitter,
View,
Animated,
} from 'react-native' ;
import PropTypes from 'prop-types' ;
import Theme from '../../../themes/Theme' ;
let keyValue = 0 ;
export default class TopView extends Component {
static add ( element) {
let key = ++ keyValue;
DeviceEventEmitter. emit ( 'addOverlay' , { key, element } ) ;
return key;
}
static remove ( key) {
DeviceEventEmitter. emit ( 'removeOverlay' , { key } ) ;
}
static removeAll ( ) {
DeviceEventEmitter. emit ( 'removeAllOverlay' , { } ) ;
}
static transform ( transform, animated, animatesOnly = null ) {
DeviceEventEmitter. emit ( 'transformRoot' , {
transform,
animated,
animatesOnly,
} ) ;
}
static restore ( animated, animatesOnly = null ) {
DeviceEventEmitter. emit ( 'restoreRoot' , { animated, animatesOnly } ) ;
}
constructor ( props) {
super ( props) ;
this . state = {
elements: [ ] ,
translateX: new Animated. Value ( 0 ) ,
translateY: new Animated. Value ( 0 ) ,
scaleX: new Animated. Value ( 1 ) ,
scaleY: new Animated. Value ( 1 ) ,
} ;
this . handlers = [ ] ;
}
static contextTypes = {
registerTopViewHandler: PropTypes. func,
unregisterTopViewHandler: PropTypes. func,
} ;
static childContextTypes = {
registerTopViewHandler: PropTypes. func,
unregisterTopViewHandler: PropTypes. func,
} ;
getChildContext ( ) {
let { registerTopViewHandler, unregisterTopViewHandler } = this . context;
if ( ! registerTopViewHandler) {
registerTopViewHandler = ( handler) => {
this . handlers. push ( handler) ;
} ;
unregisterTopViewHandler = ( handler) => {
for ( let i = this . handlers. length - 1 ; i >= 0 ; -- i) {
if ( this . handlers[ i] === handler) {
this . handlers. splice ( i, 1 ) ;
return true ;
}
}
return false ;
} ;
}
return { registerTopViewHandler, unregisterTopViewHandler } ;
}
get handler ( ) {
return this . handlers. length > 0
? this . handlers[ this . handlers. length - 1 ]
: this ;
}
componentDidMount ( ) {
let { registerTopViewHandler } = this . context;
if ( registerTopViewHandler) {
registerTopViewHandler ( this ) ;
return ;
}
DeviceEventEmitter. addListener ( 'addOverlay' , ( e) => this . handler. add ( e) ) ;
DeviceEventEmitter. addListener ( 'removeOverlay' , ( e) =>
this . handler. remove ( e) ,
) ;
DeviceEventEmitter. addListener ( 'removeAllOverlay' , ( e) =>
this . handler. removeAll ( e) ,
) ;
DeviceEventEmitter. addListener ( 'transformRoot' , ( e) =>
this . handler. transform ( e) ,
) ;
DeviceEventEmitter. addListener ( 'restoreRoot' , ( e) =>
this . handler. restore ( e) ,
) ;
}
componentWillUnmount ( ) {
let { unregisterTopViewHandler } = this . context;
if ( unregisterTopViewHandler) {
unregisterTopViewHandler ( this ) ;
return ;
}
DeviceEventEmitter. removeAllListeners ( 'addOverlay' ) ;
DeviceEventEmitter. removeAllListeners ( 'removeOverlay' ) ;
DeviceEventEmitter. removeAllListeners ( 'removeAllOverlay' ) ;
DeviceEventEmitter. removeAllListeners ( 'transformRoot' ) ;
DeviceEventEmitter. removeAllListeners ( 'restoreRoot' ) ;
}
add ( e) {
let { elements } = this . state;
elements. push ( e) ;
this . setState ( { elements } ) ;
}
remove ( e) {
let { elements } = this . state;
for ( let i = elements. length - 1 ; i >= 0 ; -- i) {
if ( elements[ i] . key === e. key) {
elements. splice ( i, 1 ) ;
break ;
}
}
this . setState ( { elements } ) ;
}
removeAll ( e) {
let { elements } = this . state;
this . setState ( { elements: [ ] } ) ;
}
transform ( e) {
let { translateX, translateY, scaleX, scaleY } = this . state;
let { transform, animated, animatesOnly } = e;
let tx = 0 ,
ty = 0 ,
sx = 1 ,
sy = 1 ;
transform. map ( ( item) => {
if ( item && typeof item === 'object' ) {
for ( let name in item) {
let value = item[ name] ;
switch ( name) {
case 'translateX' :
tx = value;
break ;
case 'translateY' :
ty = value;
break ;
case 'scaleX' :
sx = value;
break ;
case 'scaleY' :
sy = value;
break ;
}
}
}
} ) ;
if ( animated) {
let animates = [
Animated. spring ( translateX, {
toValue: tx,
friction: 9 ,
useNativeDriver: false ,
} ) ,
Animated. spring ( translateY, {
toValue: ty,
friction: 9 ,
useNativeDriver: false ,
} ) ,
Animated. spring ( scaleX, {
toValue: sx,
friction: 9 ,
useNativeDriver: false ,
} ) ,
Animated. spring ( scaleY, {
toValue: sy,
friction: 9 ,
useNativeDriver: false ,
} ) ,
] ;
animatesOnly
? animatesOnly ( animates)
: Animated. parallel ( animates) . start ( ) ;
} else {
if ( animatesOnly) {
let animates = [
Animated. timing ( translateX, {
toValue: tx,
duration: 1 ,
useNativeDriver: false ,
} ) ,
Animated. timing ( translateY, {
toValue: ty,
duration: 1 ,
useNativeDriver: false ,
} ) ,
Animated. timing ( scaleX, {
toValue: sx,
duration: 1 ,
useNativeDriver: false ,
} ) ,
Animated. timing ( scaleY, {
toValue: sy,
duration: 1 ,
useNativeDriver: false ,
} ) ,
] ;
animatesOnly ( animates) ;
} else {
translateX. setValue ( tx) ;
translateY. setValue ( ty) ;
scaleX. setValue ( sx) ;
scaleY. setValue ( sy) ;
}
}
}
restore ( e) {
let { translateX, translateY, scaleX, scaleY } = this . state;
let { animated, animatesOnly } = e;
if ( animated) {
let animates = [
Animated. spring ( translateX, {
toValue: 0 ,
friction: 9 ,
useNativeDriver: false ,
} ) ,
Animated. spring ( translateY, {
toValue: 0 ,
friction: 9 ,
useNativeDriver: false ,
} ) ,
Animated. spring ( scaleX, {
toValue: 1 ,
friction: 9 ,
useNativeDriver: false ,
} ) ,
Animated. spring ( scaleY, {
toValue: 1 ,
friction: 9 ,
useNativeDriver: false ,
} ) ,
] ;
animatesOnly
? animatesOnly ( animates)
: Animated. parallel ( animates) . start ( ) ;
} else {
if ( animatesOnly) {
let animates = [
Animated. timing ( translateX, {
toValue: 0 ,
duration: 1 ,
useNativeDriver: false ,
} ) ,
Animated. timing ( translateY, {
toValue: 0 ,
duration: 1 ,
useNativeDriver: false ,
} ) ,
Animated. timing ( scaleX, {
toValue: 1 ,
duration: 1 ,
useNativeDriver: false ,
} ) ,
Animated. timing ( scaleY, {
toValue: 1 ,
duration: 1 ,
useNativeDriver: false ,
} ) ,
] ;
animatesOnly ( animates) ;
} else {
translateX. setValue ( 0 ) ;
translateY. setValue ( 0 ) ;
scaleX. setValue ( 1 ) ;
scaleY. setValue ( 1 ) ;
}
}
}
render ( ) {
let { elements, translateX, translateY, scaleX, scaleY } = this . state;
let transform = [ { translateX } , { translateY } , { scaleX } , { scaleY } ] ;
return (
< View style= { { backgroundColor: Theme. screenColor, flex: 1 } } >
< Animated. View style= { { flex: 1 , transform: transform } } >
< PureView> { this . props. children} < / PureView>
< / Animated. View>
{ elements. map ( ( item, index) => {
return (
< View
key= { 'topView' + item. key}
style= { styles. overlay}
pointerEvents= "box-none"
>
{ item. element}
< / View>
) ;
} ) }
< / View>
) ;
}
}
var styles = StyleSheet. create ( {
overlay: {
backgroundColor: 'rgba(0, 0, 0, 0)' ,
position: 'absolute' ,
top: 0 ,
left: 0 ,
right: 0 ,
bottom: 0 ,
} ,
} ) ;
class PureView extends PureComponent {
render ( ) {
return < View style= { { flex: 1 } } > { this . props. children} < / View> ;
}
}
if ( ! AppRegistry. registerComponentOld) {
AppRegistry. registerComponentOld = AppRegistry. registerComponent;
}
AppRegistry. registerComponent = function ( appKey, componentProvider) {
class RootElement extends Component {
render ( ) {
let Component = componentProvider ( ) ;
return (
< TopView>
< Component { ... this . props} / >
< / TopView>
) ;
}
}
return AppRegistry. registerComponentOld ( appKey, ( ) => RootElement) ;
} ;
自己创建的Toast等待中的提示
import React from "react" ;
import { ActivityIndicator } from "react-native" ;
import { Toast, Theme } from "teaset" ;
let customKey = null ;
Toast. showLoading = ( text) => {
if ( customKey) return ;
customKey = Toast. show ( {
text,
icon: < ActivityIndicator size= 'large' color= { Theme. toastIconTintColor} / > ,
position: 'center' ,
duration: 100000 ,
} ) ;
}
Toast. hideLoading = ( ) => {
if ( ! customKey) return ;
Toast. hide ( customKey) ;
customKey = null ;
}
export default Toast;
如何使用刚才导入的Toast
有message、success、fail、smile、sad、info、stop、这几种提示类型 示例
import Toast from '../...'
Toast. message ( '提示文字信息' , '提示时长' , '位置' ) ;