react-native-root-toast自定義彈窗

react-native-root-toast自定義彈窗

基於版本 “react-native-root-toast”: “^3.2.1”

Toast的調用方法:

官方api提供兩種調用方式

1、Calling api

import Toast from 'react-native-root-toast';


// Add a Toast on screen.
let toast = Toast.show('This is a message', {
    duration: Toast.durations.LONG,
    position: Toast.positions.BOTTOM,
    shadow: true,
    animation: true,
    hideOnPress: true,
    delay: 0,
    onShow: () => {
        // calls on toast\`s appear animation start
    },
    onShown: () => {
        // calls on toast\`s appear animation end.
    },
    onHide: () => {
        // calls on toast\`s hide animation start.
    },
    onHidden: () => {
        // calls on toast\`s hide animation end.
    }
});

// You can manually hide the Toast, or it will automatically disappear after a `duration` ms timeout.
setTimeout(function () {
    Toast.hide(toast);
}, 500);

2、Using a Component

import React, {Component} from 'react-native';
import Toast from 'react-native-root-toast';

class Example extends Component{
    constructor() {
        super(...arguments);
        this.state = {
            visible: false
        };
    }

    componentDidMount() {
        setTimeout(() => this.setState({
            visible: true
        }), 2000); // show toast after 2s

        setTimeout(() => this.setState({
            visible: false
        }), 5000); // hide toast after 5s
    };

    render() {
        return <Toast
            visible={this.state.visible}
            position={50}
            shadow={false}
            animation={false}
            hideOnPress={true}
        >This is a message</Toast>;
    }
}
Demo中使用方法

1、簡單提示文字

import Toast from 'react-native-root-toast';
    ...
    Toast.show('正在加載...', {
        position: Toast.positions.CENTER, // toast位置
    });

效果在這裏插入圖片描述
2、自定義彈窗

    renderToast() {
        return (
            <View style={{ borderRadius: 3, backgroundColor: 'rgba(0, 0, 0, 0.8)' }}>
                <View style={styles.toastWrap}>
                    <Image style={styles.toastIcon} source={require('../../assets/image/toast/check-circle.png')} resizeMode="cover" />
                </View>
                <View style={styles.textWrap}>
                    <Text style={styles.text}>正在加載...</Text>
                </View>
            </View>
        );
    }

    showToast() {
        Toast.show(this.renderToast(), {
            position: Toast.positions.CENTER, // toast位置
        });
    }

但是發現自定義彈窗是按照設計的窗口來展現的,但是文字不顯示。
效果
在這裏插入圖片描述
查了下包內源碼。

在react-native-root-toast/lib/Toast.js中;

class Toast extends Component {
    static displayName = 'Toast';
    static propTypes = ToastContainer.propTypes;
    static positions = positions;
    static durations = durations;

    static show = (message, options = {position: positions.BOTTOM, duration: durations.SHORT}) => {
        return new RootSiblings(<ToastContainer
            {...options}
            visible={true}
        >
            {message}
        </ToastContainer>);
    };

    static hide = toast => {
        if (toast instanceof RootSiblings) {
            toast.destroy();
        } else {
            console.warn(`Toast.hide expected a \`RootSiblings\` instance as argument.\nBut got \`${typeof toast}\` instead.`);
        }
    };

    _toast = null;

    componentWillMount = () => {
        this._toast = new RootSiblings(<ToastContainer
            {...this.props}
            duration={0}
        />);
    };

    componentWillReceiveProps = nextProps => {
        this._toast.update(<ToastContainer
            {...nextProps}
            duration={0}
        />);
    };

    componentWillUnmount = () => {
        this._toast.destroy();
    };

    render() {
        return null;
    }
}

如果show傳入message的是自定義組件,那message會被包裹在在ToastContainer中,作爲ToastContainer的props.chilren

在react-native-root-toast/lib/ToastContainer.js中;

render() {
        let { props } = this;
        const { windowWidth } = this.state;
        let offset = props.position;

        const { windowHeight, keyboardScreenY } = this.state;
        const keyboardHeight = Math.max(windowHeight - keyboardScreenY, 0);
        let position = offset ? {
            [offset < 0 ? 'bottom' : 'top']: offset < 0 ? (keyboardHeight - offset) : offset
        } : {
                top: 0,
                bottom: keyboardHeight
            };

        return (this.state.visible || this._animating) ? <View
            style={[
                styles.defaultStyle,
                position
            ]}
            pointerEvents="box-none"
        >
            <TouchableWithoutFeedback
                onPress={() => {
                    typeof this.props.onPress === 'function' ? this.props.onPress() : null
                    this.props.hideOnPress ? this._hide() : null
                }}
            >
                <Animated.View
                    style={[
                        styles.containerStyle,
                        { marginHorizontal: windowWidth * ((1 - TOAST_MAX_WIDTH) / 2) },
                        props.containerStyle,
                        props.backgroundColor && { backgroundColor: props.backgroundColor },
                        {
                            opacity: this.state.opacity
                        },
                        props.shadow && styles.shadowStyle,
                        props.shadowColor && { shadowColor: props.shadowColor }
                    ]}
                    pointerEvents="none"
                    ref={ele => this._root = ele}
                >
                    <Text style={[
                        styles.textStyle,
                        props.textStyle,
                        props.textColor && { color: props.textColor }
                    ]}>
                        {this.props.children}
                    </Text>

                </Animated.View>
            </TouchableWithoutFeedback>
        </View> : null;
    }

可以看到外部傳入的message作爲this.props.children包裹在Text組件中的。

懷疑是不是下面這種嵌套結構不行,在界面中測試了一下確實不可以

    <Text >
        <View>
            <Text>Hello</Text>
        </View>
    </Text>

所以這裏對ToastContainer做了下修改

<Animated.View
                    style={[
                        styles.containerStyle,
                        { marginHorizontal: windowWidth * ((1 - TOAST_MAX_WIDTH) / 2) },
                        props.containerStyle,
                        props.backgroundColor && { backgroundColor: props.backgroundColor },
                        {
                            opacity: this.state.opacity
                        },
                        props.shadow && styles.shadowStyle,
                        props.shadowColor && { shadowColor: props.shadowColor }
                    ]}
                    pointerEvents="none"
                    ref={ele => this._root = ele}
                >
                    {/* <Text style={[
                        styles.textStyle,
                        props.textStyle,
                        props.textColor && { color: props.textColor }
                    ]}>
                        {this.props.children}
                    </Text> */}

                    {React.isValidElement(this.props.children) ? this.props.children :
                        <Text style={[
                            styles.textStyle,
                            props.textStyle,
                            props.textColor && { color: props.textColor }
                        ]}>
                            {this.props.children}
                        </Text>}
                </Animated.View>

測試下效果
在這裏插入圖片描述

OK 可以顯示完整的自定義彈窗了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章