@uiw/react-native
Version:
UIW for React Native
154 lines (147 loc) • 4.29 kB
JavaScript
import React from 'react';
import { View, StyleSheet, TouchableOpacity, Modal, Pressable, Animated } from 'react-native';
import Cloud from './Cloud';
import { getLocation, xLocation } from './utils';
export default class Tooltip extends React.Component {
fadeAnim = [new Animated.Value(0), new Animated.Value(0)];
refFollow = React.createRef();
refCloud = React.createRef();
isDown = false; // 三角 上下
isStart = xLocation.start; // 三角 左 中 右
triangle = 0; // 三角 位置
constructor(props) {
super(props);
const {
width = 100,
height = 20
} = props;
this.state = {
modalVisible: false,
cloudStyle: {
left: 0,
top: 0
},
followStyle: {
width,
height
},
modalViewStyle: {}
};
}
onOpen = () => {
this.setState({
modalVisible: true
}, () => {
this.refFollow.current && this.refFollow.current.measure((_frameOffsetX, _frameOffsetY, _width, _height, pageOffsetX, pageOffsetY) => {
this.refCloud.current && this.refCloud.current.measure((_X, _Y, _W, _H, _PX, _PY) => {
this.setState({
modalViewStyle: {
width: _width,
height: _height,
position: 'absolute',
zIndex: 9999,
left: pageOffsetX,
top: pageOffsetY
}
});
const cloudStyle = getLocation(_width, _height, pageOffsetX, pageOffsetY, _W, _H);
this.isDown = cloudStyle.isDown;
this.isStart = cloudStyle.isStart;
this.triangle = cloudStyle.triangle;
this.setState({
cloudStyle: cloudStyle.style
});
Animated.stagger(50, this.fadeAnim.map((item, index) => {
return Animated.timing(item, {
toValue: index === 0 ? 0.6 : 1,
duration: 300,
useNativeDriver: true
});
})).start(({
finished
}) => {
this.props.onOpen && this.props.onOpen();
});
});
});
});
};
onClose = () => {
Animated.stagger(50, this.fadeAnim.map(item => {
return Animated.timing(item, {
toValue: 0,
duration: 300,
useNativeDriver: true
});
}).reverse()).start(({
finished
}) => {
this.setState({
modalVisible: false
});
this.props.onClose && this.props.onClose();
});
};
render() {
const {
props: {
children,
title,
toggleAction = 'onPress',
backgroundColor = '#000',
borderRadius = 10,
...other
},
isDown
} = this;
return <View>
<Modal animationType="fade" // slide none fade
transparent={true} visible={this.state.modalVisible} {...other}>
<TouchableOpacity activeOpacity={1} style={styles.position} onPress={this.onClose}>
<Animated.View style={[styles.position, styles.backdrop, {
opacity: this.fadeAnim[0]
}]}></Animated.View>
</TouchableOpacity>
<View style={[styles.followView, { ...this.state.modalViewStyle
}]}>{children}</View>
<Animated.View style={[styles.containerView, {
opacity: this.fadeAnim[1]
}]}>
<View style={[styles.containerView, { ...this.state.cloudStyle
}]} ref={this.refCloud}>
<Cloud title={title} isDown={isDown} isStart={this.isStart} triangle={this.triangle} backgroundColor={backgroundColor} borderRadius={borderRadius} />
</View>
</Animated.View>
</Modal>
<Pressable {...{
[toggleAction]: this.onOpen
}} delayLongPress={250}>
<View style={[styles.followView, { ...this.state.followStyle
}]} ref={this.refFollow}>
{children}
</View>
</Pressable>
</View>;
}
}
const styles = StyleSheet.create({
position: {
position: 'absolute',
backgroundColor: 'transparent',
top: 0,
bottom: 0,
left: 0,
right: 0,
zIndex: 9998
},
backdrop: {
backgroundColor: '#fff'
},
containerView: {
position: 'absolute',
zIndex: 9999
},
followView: {
overflow: 'hidden'
}
});