├── .gitignore
├── LICENSE
├── demo
├── .expo-shared
│ └── assets.json
├── .gitignore
├── App.js
├── app.json
├── assets
│ ├── icon.png
│ ├── smile.png
│ ├── sound_off.png
│ ├── splash.png
│ └── view_off.png
├── babel.config.js
├── package.json
└── yarn.lock
├── index.d.ts
├── index.js
├── lib
├── Toast.js
└── ToastConstructer.js
├── package-lock.json
├── package.json
├── readme.md
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 | web-report/
12 |
13 | # macOS
14 | .DS_Store
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Barba Lee
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/demo/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 | }
5 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/demo/App.js:
--------------------------------------------------------------------------------
1 | import { View, StyleSheet, Text, TouchableOpacity, Image, ScrollView } from 'react-native';
2 | import React, { Component } from 'react';
3 | import Toast, { Duration, Position } from 'react-native-mix-toast';
4 |
5 | class MixToastExample extends Component {
6 | getToast1 = () => {
7 | Toast.show('Default Toast');
8 | };
9 | getToast10 = () => {
10 | Toast.show('View Off',
11 | {
12 | icon: require('./assets/view_off.png'),
13 | }
14 | );
15 | };
16 | getToast11 = () => {
17 | Toast.show('View Off',
18 | {
19 | icon: ,
20 | }
21 | );
22 | };
23 | getToast2 = () => {
24 | Toast.show('Duration === LONG', {
25 | duration: Duration.LONG
26 | });
27 | };
28 | getToast3 = () => {
29 | Toast.show('Position === Top', {
30 | position: Position.TOP
31 | });
32 | };
33 | getToast4 = () => {
34 | Toast.show('Slide Animation', {
35 | animation: 'slide-right'
36 | });
37 | };
38 | getToast40 = () => {
39 | Toast.show('Scale Animation 2', {
40 | animation: 'scale'
41 | });
42 | };
43 | getToast5 = () => {
44 | Toast.show('Press To Hide', {
45 | hideOnPress: true,
46 | onPress: () => {
47 | alert('Press to hide the toast');
48 | }
49 | });
50 | };
51 | getToast6 = () => {
52 | Toast.show('Lifecycle on Console', {
53 | onShow: () => {
54 | console.log('Toast Show Start');
55 | },
56 | onShown: () => {
57 | console.log('Toast Show End');
58 | },
59 | onHide: () => {
60 | console.log('Toast Hide Start');
61 | },
62 | onHidden: () => {
63 | console.log('Toast Hide End');
64 | }
65 | });
66 | };
67 | _toast = null
68 | getToast60 = () => {
69 | this._toast = Toast.show('Touch PressToHide Will Hide The Toast', {
70 | duration: Duration.PERSIST
71 | });
72 | };
73 | getToast61 = () => {
74 | Toast.hide(this._toast)
75 | };
76 | getToast62 = () => {
77 | this._toast = Toast.show('I am happy', {
78 | icon: ,
79 | });
80 | };
81 | getToast63 = () => {
82 | Toast.update(this._toast, 'You are happy', {
83 | icon: ,
84 | })
85 | };
86 | getToast7 = () => {
87 | Toast.show('Changed ToastSTyle', {
88 | toastStyle: { backgroundColor: 'yellowgreen' }
89 | });
90 | };
91 | getToast70 = () => {
92 | Toast.show('Changed TextSTyle', {
93 | textStyle: { color: 'yellowgreen', fontWeight: 'bold' }
94 | });
95 | };
96 | getToast71 = () => {
97 | Toast.show('Changed IconSTyle', {
98 | iconStyle: { backgroundColor: 'yellowgreen' },
99 | icon: require('./assets/view_off.png'),
100 | });
101 | };
102 | getToast8 = () => {
103 |
104 |
105 | ,
106 | Toast.show(
107 |
108 |
109 | you will smile
110 |
111 | );
112 | };
113 | getToast9 = () => {
114 | Toast.show(
115 |
116 |
117 | ,
118 | {
119 | custom: true,
120 | animation: 'slide-bottom',
121 | opacity: 1
122 | }
123 | );
124 | };
125 | getToast10 = () => {
126 | Toast.show(
127 |
128 |
129 | ,
130 | {
131 | position: 300,
132 | custom: true,
133 | animation: 'scale',
134 | opacity: 1,
135 | mask: true
136 | }
137 | );
138 | };
139 |
140 | _myToast = null
141 | _mySound = 50
142 | myToast1 = () => {
143 | this._myToast = Toast.show(
144 | this.iosNaitveSound(),
145 | {
146 | custom: true,
147 | animation: 'slide-top',
148 | opacity: 1,
149 | position: 40
150 | }
151 | );
152 | }
153 | myToast2 = () => {
154 | if (this._mySound < 120) { this._mySound += 5 };
155 | Toast.update(
156 | this._myToast,
157 | this.iosNaitveSound(),
158 | {
159 | custom: true,
160 | animation: 'slide-top',
161 | opacity: 1,
162 | position: 40
163 | }
164 | );
165 | }
166 | iosNaitveSound = () => {
167 | return
168 |
169 |
170 | 铃声
171 |
172 |
173 |
174 | }
175 |
176 | myToast3 = () => {
177 | this._myToast = Toast.show(
178 | this.androidSound(),
179 | {
180 | custom: true,
181 | animation: 'slide-right',
182 | opacity: 1,
183 | position: Position.CENTER
184 | }
185 | );
186 | }
187 | myToast4 = () => {
188 | if (this._mySound > 0) { this._mySound -= 5 };
189 | Toast.update(
190 | this._myToast,
191 | this.androidSound(),
192 | {
193 | custom: true,
194 | animation: 'slide-right',
195 | opacity: 1,
196 | position: Position.CENTER
197 | }
198 | );
199 | }
200 | androidSound = () => {
201 | return
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 | }
210 |
211 |
212 |
213 | render () {
214 | return (
215 |
216 |
217 | Mix Toast Demo
218 |
219 | Default Toast
220 |
221 |
222 | Duration Long
223 |
224 |
225 | Position Top
226 |
227 |
228 |
229 | Icon
230 |
231 |
232 | Icon2
233 |
234 |
235 |
236 | Slide Animation
237 |
238 |
239 | Scale Animation
240 |
241 |
242 | Press To Hide
243 |
244 |
245 | Lifecycle
246 |
247 |
248 |
249 | ToShow
250 |
251 |
252 | ToHide
253 |
254 |
255 |
256 |
257 | ToShow
258 |
259 |
260 | ToUpdate
261 |
262 |
263 |
264 | ToastStyle
265 |
266 |
267 | TextSTyle
268 |
269 |
270 | IconStyle
271 |
272 |
273 | Node Message
274 |
275 |
276 | Custom Node Message
277 |
278 |
279 | Node With Mask
280 |
281 |
282 |
283 | iOS Native
284 |
285 | Show Sound
286 |
287 |
288 | Update Sound
289 |
290 | Android Sound
291 |
292 | Show Sound
293 |
294 |
295 | Update Sound
296 |
297 |
298 |
299 |
300 | );
301 | }
302 | }
303 | export default MixToastExample;
304 |
305 | const styles = StyleSheet.create({
306 | container: {
307 | marginVertical: 100,
308 | justifyContent: 'center',
309 | alignItems: 'center'
310 | },
311 | header: {
312 | margin: 10,
313 | fontSize: 42,
314 | fontWeight: 'bold',
315 | color: 'green'
316 | },
317 | text: {
318 | margin: 10,
319 | fontSize: 30,
320 | fontWeight: 'bold',
321 | color: 'yellowgreen',
322 | },
323 | custom: {
324 | backgroundColor: 'white',
325 | borderRadius: 10,
326 | padding: 10,
327 | shadowOpacity: 0.2,
328 | shadowColor: '#000',
329 | shadowRadius: 3,
330 | elevation: 3,
331 | },
332 | iosNaitve: {
333 | width: 200,
334 | backgroundColor: '#f5f6f2',
335 | borderRadius: 50,
336 | padding: 12,
337 | shadowOpacity: 0.2,
338 | shadowColor: '#000',
339 | shadowRadius: 30,
340 | elevation: 3,
341 | alignItems: 'center',
342 | flexDirection: 'row'
343 | },
344 | androidSound: {
345 | width: 375,
346 | justifyContent: 'center',
347 | alignItems: 'flex-end',
348 | shadowOpacity: 0.2,
349 | shadowColor: '#000',
350 | shadowRadius: 10,
351 | elevation: 2,
352 | }
353 | });
354 |
--------------------------------------------------------------------------------
/demo/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "demo",
4 | "slug": "demo",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": [
17 | "**/*"
18 | ],
19 | "ios": {
20 | "supportsTablet": true
21 | },
22 | "web": {
23 | "favicon": "./assets/favicon.png"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Barba828/react-native-mix-toast/baff135f0afeda8a4e9f8ee7df2bb601d2fba2df/demo/assets/icon.png
--------------------------------------------------------------------------------
/demo/assets/smile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Barba828/react-native-mix-toast/baff135f0afeda8a4e9f8ee7df2bb601d2fba2df/demo/assets/smile.png
--------------------------------------------------------------------------------
/demo/assets/sound_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Barba828/react-native-mix-toast/baff135f0afeda8a4e9f8ee7df2bb601d2fba2df/demo/assets/sound_off.png
--------------------------------------------------------------------------------
/demo/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Barba828/react-native-mix-toast/baff135f0afeda8a4e9f8ee7df2bb601d2fba2df/demo/assets/splash.png
--------------------------------------------------------------------------------
/demo/assets/view_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Barba828/react-native-mix-toast/baff135f0afeda8a4e9f8ee7df2bb601d2fba2df/demo/assets/view_off.png
--------------------------------------------------------------------------------
/demo/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "react-native-mix-toast":"^0.1.1",
12 | "react-native-root-siblings": "^4.0.6",
13 | "expo": "~39.0.2",
14 | "expo-calendar": "~8.5.0",
15 | "expo-status-bar": "~1.0.2",
16 | "react": "16.13.1",
17 | "react-dom": "16.13.1",
18 | "react-native": "https://github.com/expo/react-native/archive/sdk-39.0.2.tar.gz",
19 | "react-native-web": "~0.13.12"
20 | },
21 | "devDependencies": {
22 | "@babel/core": "~7.9.0"
23 | },
24 | "private": true
25 | }
26 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | import Toast from './lib/Toast';
2 | import { positions, durations } from './lib/ToastConstructer';
3 |
4 | export { durations as Duration };
5 | export { positions as Position };
6 | export default Toast;
7 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import Toast from './lib/Toast';
2 | import { positions, durations } from './lib/ToastConstructer';
3 |
4 | export { durations as Duration };
5 | export { positions as Position };
6 | export default Toast;
7 |
--------------------------------------------------------------------------------
/lib/Toast.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import RootSiblings from 'react-native-root-siblings';
3 | import ToastConstructer, { positions, durations } from './ToastConstructer';
4 |
5 | class Toast extends Component {
6 | static displayName = 'Toast';
7 | static propTypes = ToastConstructer.propTypes;
8 | static positions = positions;
9 | static durations = durations;
10 |
11 | constructor(props) {
12 | super(props);
13 | }
14 |
15 | //生产toast实例
16 | static show = (
17 | message,
18 | options = {
19 | position: positions.BOTTOM,
20 | duration: durations.SHORT
21 | },
22 | ) => {
23 | //new Toast对象实例
24 | let toast = new RootSiblings(
25 | (
26 | {
29 | this.hide(toast)
30 | }}
31 | {...options}>
32 | {message}
33 |
34 | ),
35 | );
36 | return toast
37 | };
38 |
39 | static update = (
40 | toast,
41 | message,
42 | options = {
43 | position: positions.BOTTOM,
44 | duration: durations.SHORT
45 | }, ) => {
46 | //判断toast类型
47 | if (toast instanceof RootSiblings) {
48 | toast.update(
49 | {
52 | this.hide(toast)
53 | }}
54 | {...options}>
55 | {message}
56 |
57 | )
58 | } else {
59 | console.warn(
60 | `Toast.hide expected a \`RootSiblings\` instance as argument.\nBut got \`${typeof toast}\` instead.`,
61 | );
62 | }
63 | }
64 |
65 | //销毁toast实例
66 | static hide = toast => {
67 | //判断toast类型
68 | if (toast instanceof RootSiblings) {
69 | toast.destroy();
70 | } else {
71 | console.warn(
72 | `Toast.hide expected a \`RootSiblings\` instance as argument.\nBut got \`${typeof toast}\` instead.`,
73 | );
74 | }
75 | };
76 | }
77 |
78 | export { RootSiblings as Manager };
79 | export default Toast;
80 |
--------------------------------------------------------------------------------
/lib/ToastConstructer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | ViewPropTypes,
5 | StyleSheet,
6 | View,
7 | Text,
8 | Animated,
9 | Dimensions,
10 | TouchableWithoutFeedback,
11 | Easing,
12 | Keyboard,
13 | Image
14 | } from 'react-native';
15 | const window = Dimensions.get('window');
16 | /**
17 | * Toast展示位置
18 | * @TOP top:20%
19 | * @CENTER top:50%
20 | * @BOTTOM top:80%
21 | */
22 | const positions = {
23 | TOP: window.height * 0.2,
24 | BOTTOM: window.height * 0.8,
25 | CENTER: window.height * 0.5,
26 | };
27 | /**
28 | * Toast展示时间
29 | * @LONG 3500ms
30 | * @SHORT 2000ms
31 | * @PERSIST 永久展示
32 | */
33 | const durations = {
34 | LONG: 3500,
35 | SHORT: 2000,
36 | PERSIST: Infinity,
37 | };
38 |
39 | const MAX_WIDTH = 0.8;
40 | const MIN_WIDTH = 0.4;
41 | const ANIMATION_DURATION = 200;
42 |
43 | class ToastConstructor extends Component {
44 | constructor(props) {
45 | super(props);
46 | this.state = {
47 | visible: false,
48 | animatedValue: new Animated.Value(0),//动画状态值
49 | windowWidth: window.width,
50 | windowHeight: window.height,
51 | keyboardScreenY: window.height,
52 | };
53 | //渐入动画
54 | this.animatedValueStart = Animated.timing(this.state.animatedValue, {
55 | toValue: 100,
56 | duration: ANIMATION_DURATION,
57 | easing: Easing.out(Easing.ease),
58 | useNativeDriver:false,
59 | })
60 | //渐出动画
61 | this.animatedValueEnd = Animated.timing(this.state.animatedValue, {
62 | toValue: 0,
63 | duration: ANIMATION_DURATION,
64 | easing: Easing.in(Easing.ease),
65 | useNativeDriver:false,
66 | })
67 | //展示定时器
68 | this.Timeout = null;
69 | this.ttt = null
70 | }
71 |
72 | componentDidMount () {
73 | // 响应式改变布局
74 | Dimensions.addEventListener('change', () => {
75 | this.setState({
76 | windowWidth: window.width,
77 | windowHeight: window.height,
78 | });
79 | });
80 | this.props.keyboardAvoiding && Keyboard.addListener(
81 | 'keyboardDidChangeFrame',
82 | (endCoordinates) => {
83 | this.setState({
84 | keyboardScreenY: endCoordinates.screenY,
85 | });
86 | },
87 | );
88 | //new =>启动定时器开始show
89 | this.Timeout = setTimeout(() => this._show(), this.props.delay);
90 | }
91 |
92 | UNSAFE_componentWillReceiveProps (nextProps) {
93 | //update =>更新定时器和显示参数
94 | clearTimeout(this.Timeout);
95 | this.Timeout = setTimeout(() => {
96 | this._hide()
97 | }, nextProps.duration);
98 | }
99 | componentWillUnmount () {
100 | //hide =>清除定时器和监听
101 | clearTimeout(this.Timeout)
102 | Dimensions.removeEventListener('change');
103 | Keyboard.removeListener('keyboardDidChangeFrame');
104 | };
105 |
106 | /**
107 | * 定义动画
108 | */
109 | _animated () {
110 | let animate = {
111 | opacity: this.state.animatedValue.interpolate({
112 | inputRange: [0, 100],
113 | outputRange: [0, this.props.opacity]
114 | })
115 | }
116 | switch (this.props.animation) {
117 | case 'fade':
118 | break
119 | case 'slide-right':
120 | animate.transform = [{
121 | translateX: this.state.animatedValue.interpolate({
122 | inputRange: [0, 100],
123 | outputRange: [window.width / 2, 0]
124 | })
125 | }]
126 | break
127 | case 'slide-left':
128 | animate.transform = [{
129 | translateX: this.state.animatedValue.interpolate({
130 | inputRange: [0, 100],
131 | outputRange: [-window.width / 2, 0]
132 | })
133 | }]
134 | break
135 | case 'slide-bottom':
136 | animate.transform = [{
137 | translateY: this.state.animatedValue.interpolate({
138 | inputRange: [0, 100],
139 | outputRange: [this.props.position, 0]
140 | })
141 | }]
142 | break
143 | case 'slide-top':
144 | animate.transform = [{
145 | translateY: this.state.animatedValue.interpolate({
146 | inputRange: [0, 100],
147 | outputRange: [-this.props.position, 0]
148 | })
149 | }]
150 | break
151 | case 'scale':
152 | animate.transform = [{
153 | scaleX: this.state.animatedValue.interpolate({
154 | inputRange: [0, 100],
155 | outputRange: [0.1, 1]
156 | }),
157 | },
158 | {
159 | scaleY: this.state.animatedValue.interpolate({
160 | inputRange: [0, 100],
161 | outputRange: [0.1, 1]
162 | })
163 | }]
164 | break
165 | case 'scale-vertical':
166 | animate.transform = [
167 | {
168 | scaleY: this.state.animatedValue.interpolate({
169 | inputRange: [0, 100],
170 | outputRange: [0.1, 1]
171 | })
172 | }]
173 | break
174 | case 'scale-horizontal':
175 | animate.transform = [{
176 | scaleX: this.state.animatedValue.interpolate({
177 | inputRange: [0, 100],
178 | outputRange: [0.1, 1]
179 | }),
180 | }]
181 | break
182 | default:
183 | break;
184 | }
185 | return animate
186 | }
187 |
188 | /**
189 | * 定义遮罩层mask动画
190 | */
191 | _maskAnimated () {
192 | return {
193 | backgroundColor: this.state.animatedValue.interpolate({
194 | inputRange: [0, 100],
195 | outputRange: ["#0000", "#0003"]
196 | })
197 | }
198 | }
199 |
200 | /**
201 | * 执行点击事件方法
202 | * @param {object} event
203 | */
204 | _onPress (event) {
205 | this.props.onPress && this.props.onPress(event);
206 | this.props.hideOnPress && this._hide();
207 | }
208 |
209 | /**
210 | * 展示toast
211 | */
212 | _show () {
213 | clearTimeout(this.Timeout)
214 | this.props.onShow && this.props.onShow();
215 | this.setState({ visible: true }, () => {
216 | this.animatedValueStart.start(() => {
217 | this.props.onShown && this.props.onShown();
218 | //执行消失方法
219 | this.props.duration !== durations.PERSIST && (this.Timeout = setTimeout(() => {
220 | this._hide()
221 | }, this.props.duration))
222 | })
223 | })
224 | }
225 |
226 | /**
227 | * 消失toast
228 | */
229 | _hide () {
230 | clearTimeout(this.Timeout)
231 | this.props.onHide && this.props.onHide();
232 | this.animatedValueEnd.start(() => {
233 | this.props.onHidden && this.props.onHidden();
234 | this.setState({ visible: false }, () => {
235 | //销毁本组件
236 | this.props.destroyToast()
237 | })
238 | })
239 | }
240 |
241 | /**
242 | * toast内容
243 | */
244 | renderContent () {
245 | const { position, custom, children, icon, toastStyle, textStyle, iconStyle, onPress, hideOnPress, touchable } = this.props;
246 | const { windowWidth, windowHeight, keyboardScreenY } = this.state;
247 | const heightRate = (keyboardScreenY / windowHeight)||1;
248 | let offset = { top: position * heightRate }
249 | return (
250 |
251 | this._onPress(event)} pointerEvents="none">
252 |
253 | {custom
254 | ? {typeof children === "string"
255 | ? {children}
256 | : (children)}
257 |
258 | :
262 | {typeof children === "string"
263 | ? (
264 | {icon && typeof icon === 'number'
265 | ?
266 | : icon}
267 | {children}
268 | )
269 | : (children)}
270 | }
271 |
272 |
273 |
274 | )
275 | }
276 |
277 | render () {
278 | const { mask } = this.props;
279 | const { visible } = this.state;
280 | return visible
281 | ? mask
282 | ?
283 | {this.renderContent()}
284 |
285 | : this.renderContent()
286 | : null
287 | }
288 | }
289 |
290 | const styles = StyleSheet.create({
291 | container: {
292 | position: 'absolute',
293 | left: 0,
294 | right: 0,
295 | justifyContent: 'center',
296 | alignItems: 'center',
297 | zIndex: 9999,
298 | },
299 | toast: {
300 | padding: 8,
301 | paddingHorizontal: 12,
302 | backgroundColor: '#000',
303 | borderRadius: 6,
304 | minHeight: 44,
305 | },
306 | mask: {
307 | width: window.width,
308 | height: window.height,
309 | position: 'absolute',
310 | backgroundColor: '#0003'
311 | },
312 | view: {
313 | justifyContent: 'center',
314 | alignItems: 'center'
315 | },
316 | text: {
317 | fontSize: 16,
318 | color: '#fff',
319 | textAlign: 'center',
320 | lineHeight: 28,
321 | },
322 | icon: {
323 | width: 32,
324 | height: 32,
325 | resizeMode: 'contain'
326 | }
327 | })
328 |
329 | /**
330 | * 定义参数类型
331 | */
332 | ToastConstructor.propTypes = {
333 | ...ViewPropTypes,
334 | children: PropTypes.oneOfType([
335 | PropTypes.string,
336 | PropTypes.node
337 | ]),
338 | duration: PropTypes.number,
339 | position: PropTypes.number,
340 | mask: PropTypes.bool,
341 | opacity: PropTypes.number,
342 | delay: PropTypes.number,
343 | animation: PropTypes.string,
344 | custom: PropTypes.bool,
345 | keyboardAvoiding: PropTypes.bool,
346 | hideOnPress: PropTypes.bool,
347 | toastStyle: ViewPropTypes.style,
348 | textStyle: Text.propTypes.style,
349 | onPress: PropTypes.func,
350 | onHide: PropTypes.func,
351 | onHidden: PropTypes.func,
352 | onShow: PropTypes.func,
353 | onShown: PropTypes.func,
354 | }
355 |
356 | /**
357 | * 默认参数值
358 | */
359 | ToastConstructor.defaultProps = {
360 | duration: durations.SHORT,
361 | position: positions.BOTTOM,
362 | mask: false,
363 | custom: false,
364 | opacity: 0.8,
365 | delay: 0,
366 | hideOnPress: false,
367 | keyboardAvoiding: true,
368 | }
369 |
370 | export default ToastConstructor;
371 | export { positions, durations };
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-mix-toast",
3 | "version": "0.0.8",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "react-native-root-siblings": {
8 | "version": "4.0.6",
9 | "resolved": "https://registry.npmjs.org/react-native-root-siblings/-/react-native-root-siblings-4.0.6.tgz",
10 | "integrity": "sha512-u/MaJLdD3bnshDFg8HWB0Xys1xlkQy6++3QthQlYw4kOFElobb6V1IIn5r46JvBTr9cf6dXsrFC4zPVXuwW1ww==",
11 | "requires": {
12 | "static-container": "^1.5.1"
13 | }
14 | },
15 | "static-container": {
16 | "version": "1.5.1",
17 | "resolved": "https://registry.npmjs.org/static-container/-/static-container-1.5.1.tgz",
18 | "integrity": "sha512-OFChfLKIvSzaMA3otS5CEabJTIzHFPhMxogIT+io4F207PXTvS6woFyjXIyXyqMIYAhryePGeFZYC6uLcG1lpA=="
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-mix-toast",
3 | "version": "0.1.2",
4 | "description": "react-native toast with animation for iOS & Android",
5 | "main": "index.js",
6 | "directories": {
7 | "lib": "lib"
8 | },
9 | "files": [
10 | "lib",
11 | "index.js",
12 | "index.d.ts"
13 | ],
14 | "scripts": {
15 | "test": "echo \"Error: no test specified\" && exit 1"
16 | },
17 | "dependencies": {
18 | "react-native-root-siblings": "^4.0.6"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "git+https://github.com/Barba828/react-native-mix-toast.git"
23 | },
24 | "keywords": [
25 | "react-native",
26 | "toast",
27 | "android",
28 | "ios"
29 | ],
30 | "author": "Barba Lee",
31 | "license": "ISC",
32 | "bugs": {
33 | "url": "https://github.com/Barba828/react-native-mix-toast/issues"
34 | },
35 | "homepage": "https://github.com/Barba828/react-native-mix-toast#readme",
36 | "devDependencies": {
37 | "tern": "^0.24.3"
38 | }
39 | }
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # react-native-mix-toast 轻提示
2 | [](https://www.npmjs.com/package/react-native-mix-toast)
3 | [](https://www.npmjs.com/package/react-native-mix-toast)
4 | [](https://github.com/Barba828/react-native-mix-toast/blob/master/LICENSE)
5 | [](https://github.com/Barba828/react-native-mix-toast/stargazers)
6 |
7 | ## DESCRIBE
8 | Android和iOS平台通用的自定义Toast UI组件
9 |
10 | ## USAGE
11 |
12 | ### INSTALL
13 | ```shell
14 | npm install react-native-mix-toast
15 | ```
16 |
17 | ### IMPORT
18 | ```js
19 | import Toast, { Duration, Position } from 'react-native-mix-toast';
20 | ```
21 | ### EXAMPLE
22 | ```js
23 | Toast.show('This is Toast', {
24 | duration: Duration.LONG,
25 | });
26 | ```
27 |
28 | ## FUNC
29 |
30 | ### show(content,{options})
31 | 显示Toast
32 | 属性 | 说明 | 类型 | 默认值
33 | ----|-----|------|------
34 | | content | Toast显示文本内容,可为`React.Node` | `string`、`node` | - |
35 | | {options} | Toast显示参数[API](##API) | `object` | - |
36 |
37 | ### update(toast,content,{options})
38 | 更新Toast
39 | 属性 | 说明 | 类型 | 默认值
40 | ----|-----|------|------
41 | | toast | 需要更新的toast | `object` | - |
42 | | content | 同`show()` | `string`、`node` | - |
43 | | {options} | 同`show()` | `object` | - |
44 |
45 | ### hide(toast)
46 | 可以主动调用关闭Toast
47 | 属性 | 说明 | 类型 | 默认值
48 | ----|-----|------|------
49 | | toast | 需要更新的toast | `object` | - |
50 |
51 | ### EXAMPLE
52 | ```js
53 | // show()
54 | var myToast = Toast.show(
55 | 'This is Toast',
56 | { duration: Duration.PERSIST }
57 | );
58 | // update()
59 | Toast.update(
60 | myToast,
61 | 'This is Updated Toast',
62 | { duration: Duration.PERSIST }
63 | );
64 | // hide()
65 | Toast.hide(myToast)
66 | ```
67 |
68 | ## API
69 | 属性 | 说明 | 类型
70 | ----|-----|------
71 | | content | Toast显示文本内容,也可传入`React.Node` | `string`、`node` |
72 | | options | Toast显示设置 | `object` |
73 |
74 | ### OPTIONS
75 | 属性 | 说明 | 类型 | 默认值
76 | ----|-----|------|------
77 | | duration | 显示时间,默认提供`LONG`,`SHORT`,`PERSIST` | `number` | `SHORT` |
78 | | position | 显示位置,默认提供`BOTTOM`,`TOP`,`CENTER` | `number` | `BOTTOM` |
79 | | mask | 遮罩层 | `bool` | `false` |
80 | | icon | 显示图标 | `number`、`node` | - |
81 | | opacity | 显示透明度 | `number` | `0.8` |
82 | | delay | 延时显示 | `number` | `0` |
83 | | animation | 渐入渐出动画,默认提供`fade`,`slide-right`,`slide-left`,`slide-bottom`,`slide-top`,`scale`,`scale-vertical`,`scale-horizontal` | `string` | `fade` |
84 | | custom | 完全自定义显示内容 | `boolean` | `false` |
85 | | keyboardAvoiding | 避免键盘遮挡 | `boolean` | `true` |
86 | | toastStyle| Toast自定义样式 | `object` | - |
87 | | textStyle | Toast文本自定义样式 | `object` | - |
88 | | iconStyle | Toast图标自定义样式 | `object` | - |
89 | | touchable | 可点击内容 | `object` | - |
90 | | hideOnPress | 点击取消显示 | `boolean` | `fasle` |
91 | | onPress | 点击Toast触发事件 | `function` | - |
92 | | onShow | 显示动画开始调用函数 | `function` | - |
93 | | onShown | 显示动画结束调用函数 | `function` | - |
94 | | onHide | 消失动画开始调用函数 | `function` | - |
95 | | onHidden | 消失动画结束调用函数 | `function` | - |
96 |
97 | ## DEMO
98 | ```shell
99 | cd demo
100 | npm install
101 | npm start
102 | ```
103 | or
104 |
105 | [](https://expo.io/@barba-lee/demo)
106 |
107 |
108 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | acorn-loose@^6.0.0:
6 | version "6.1.0"
7 | resolved "https://registry.npm.taobao.org/acorn-loose/download/acorn-loose-6.1.0.tgz#3b2de5b3fc64f811c7b6c07cd9128d1476817f94"
8 | integrity sha1-Oy3ls/xk+BHHtsB82RKNFHaBf5Q=
9 | dependencies:
10 | acorn "^6.2.0"
11 |
12 | acorn-walk@^6.0.0:
13 | version "6.2.0"
14 | resolved "https://registry.npm.taobao.org/acorn-walk/download/acorn-walk-6.2.0.tgz?cache=0&sync_timestamp=1597235826369&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-walk%2Fdownload%2Facorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c"
15 | integrity sha1-Ejy487hMIXHx9/slJhWxx4prGow=
16 |
17 | acorn@^6.0.0, acorn@^6.2.0:
18 | version "6.4.1"
19 | resolved "https://registry.npm.taobao.org/acorn/download/acorn-6.4.1.tgz?cache=0&sync_timestamp=1597235823632&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
20 | integrity sha1-Ux5Yuj9RudrLmmZGyk3r9bFMpHQ=
21 |
22 | balanced-match@^1.0.0:
23 | version "1.0.0"
24 | resolved "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
25 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
26 |
27 | brace-expansion@^1.1.7:
28 | version "1.1.11"
29 | resolved "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
30 | integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=
31 | dependencies:
32 | balanced-match "^1.0.0"
33 | concat-map "0.0.1"
34 |
35 | concat-map@0.0.1:
36 | version "0.0.1"
37 | resolved "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
38 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
39 |
40 | core-util-is@~1.0.0:
41 | version "1.0.2"
42 | resolved "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
43 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
44 |
45 | enhanced-resolve@^2.2.2:
46 | version "2.3.0"
47 | resolved "https://registry.npm.taobao.org/enhanced-resolve/download/enhanced-resolve-2.3.0.tgz?cache=0&sync_timestamp=1600384940681&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenhanced-resolve%2Fdownload%2Fenhanced-resolve-2.3.0.tgz#a115c32504b6302e85a76269d7a57ccdd962e359"
48 | integrity sha1-oRXDJQS2MC6Fp2Jp16V8zdli41k=
49 | dependencies:
50 | graceful-fs "^4.1.2"
51 | memory-fs "^0.3.0"
52 | object-assign "^4.0.1"
53 | tapable "^0.2.3"
54 |
55 | errno@^0.1.3:
56 | version "0.1.7"
57 | resolved "https://registry.npm.taobao.org/errno/download/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
58 | integrity sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=
59 | dependencies:
60 | prr "~1.0.1"
61 |
62 | fs.realpath@^1.0.0:
63 | version "1.0.0"
64 | resolved "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
65 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
66 |
67 | glob@^7.1.1:
68 | version "7.1.6"
69 | resolved "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz?cache=0&sync_timestamp=1586263931536&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglob%2Fdownload%2Fglob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
70 | integrity sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY=
71 | dependencies:
72 | fs.realpath "^1.0.0"
73 | inflight "^1.0.4"
74 | inherits "2"
75 | minimatch "^3.0.4"
76 | once "^1.3.0"
77 | path-is-absolute "^1.0.0"
78 |
79 | graceful-fs@^4.1.2:
80 | version "4.2.4"
81 | resolved "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
82 | integrity sha1-Ila94U02MpWMRl68ltxGfKB6Kfs=
83 |
84 | inflight@^1.0.4:
85 | version "1.0.6"
86 | resolved "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
87 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
88 | dependencies:
89 | once "^1.3.0"
90 | wrappy "1"
91 |
92 | inherits@2, inherits@~2.0.3:
93 | version "2.0.4"
94 | resolved "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
95 | integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=
96 |
97 | isarray@~1.0.0:
98 | version "1.0.0"
99 | resolved "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
100 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
101 |
102 | memory-fs@^0.3.0:
103 | version "0.3.0"
104 | resolved "https://registry.npm.taobao.org/memory-fs/download/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20"
105 | integrity sha1-e8xrYp46Q+hx1+Kaymrop/FcuyA=
106 | dependencies:
107 | errno "^0.1.3"
108 | readable-stream "^2.0.1"
109 |
110 | minimatch@^3.0.3, minimatch@^3.0.4:
111 | version "3.0.4"
112 | resolved "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz?cache=0&sync_timestamp=1597044082534&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminimatch%2Fdownload%2Fminimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
113 | integrity sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=
114 | dependencies:
115 | brace-expansion "^1.1.7"
116 |
117 | object-assign@^4.0.1:
118 | version "4.1.1"
119 | resolved "https://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
120 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
121 |
122 | once@^1.3.0:
123 | version "1.4.0"
124 | resolved "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
125 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
126 | dependencies:
127 | wrappy "1"
128 |
129 | path-is-absolute@^1.0.0:
130 | version "1.0.1"
131 | resolved "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
132 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
133 |
134 | process-nextick-args@~2.0.0:
135 | version "2.0.1"
136 | resolved "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
137 | integrity sha1-eCDZsWEgzFXKmud5JoCufbptf+I=
138 |
139 | prr@~1.0.1:
140 | version "1.0.1"
141 | resolved "https://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
142 | integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
143 |
144 | react-native-root-siblings@^4.0.6:
145 | version "4.0.6"
146 | resolved "https://registry.npm.taobao.org/react-native-root-siblings/download/react-native-root-siblings-4.0.6.tgz#6dd7eedb725faacd7ba19c159dd279cf2e6d8476"
147 | integrity sha1-bdfu23Jfqs17oZwVndJ5zy5thHY=
148 | dependencies:
149 | static-container "^1.5.1"
150 |
151 | readable-stream@^2.0.1:
152 | version "2.3.7"
153 | resolved "https://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
154 | integrity sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c=
155 | dependencies:
156 | core-util-is "~1.0.0"
157 | inherits "~2.0.3"
158 | isarray "~1.0.0"
159 | process-nextick-args "~2.0.0"
160 | safe-buffer "~5.1.1"
161 | string_decoder "~1.1.1"
162 | util-deprecate "~1.0.1"
163 |
164 | resolve-from@2.0.0:
165 | version "2.0.0"
166 | resolved "https://registry.npm.taobao.org/resolve-from/download/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
167 | integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=
168 |
169 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
170 | version "5.1.2"
171 | resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
172 | integrity sha1-mR7GnSluAxN0fVm9/St0XDX4go0=
173 |
174 | static-container@^1.5.1:
175 | version "1.5.1"
176 | resolved "https://registry.npm.taobao.org/static-container/download/static-container-1.5.1.tgz#9d7a94e04dea864539a7b6a1304843ada740dc19"
177 | integrity sha1-nXqU4E3qhkU5p7ahMEhDradA3Bk=
178 |
179 | string_decoder@~1.1.1:
180 | version "1.1.1"
181 | resolved "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
182 | integrity sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=
183 | dependencies:
184 | safe-buffer "~5.1.0"
185 |
186 | tapable@^0.2.3:
187 | version "0.2.9"
188 | resolved "https://registry.npm.taobao.org/tapable/download/tapable-0.2.9.tgz#af2d8bbc9b04f74ee17af2b4d9048f807acd18a8"
189 | integrity sha1-ry2LvJsE907hevK02QSPgHrNGKg=
190 |
191 | tern@^0.24.3:
192 | version "0.24.3"
193 | resolved "https://registry.npm.taobao.org/tern/download/tern-0.24.3.tgz#da0d9118490c15af4b1c94553d5f0fafc77a0977"
194 | integrity sha1-2g2RGEkMFa9LHJRVPV8Pr8d6CXc=
195 | dependencies:
196 | acorn "^6.0.0"
197 | acorn-loose "^6.0.0"
198 | acorn-walk "^6.0.0"
199 | enhanced-resolve "^2.2.2"
200 | glob "^7.1.1"
201 | minimatch "^3.0.3"
202 | resolve-from "2.0.0"
203 |
204 | util-deprecate@~1.0.1:
205 | version "1.0.2"
206 | resolved "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
207 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
208 |
209 | wrappy@1:
210 | version "1.0.2"
211 | resolved "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
212 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
213 |
--------------------------------------------------------------------------------