RN中結合Animated封裝一個簡單的Toast組件

直接上代碼

import React, {Component} from 'react';
import {StyleSheet, Dimensions, Animated, Easing} from 'react-native';
import PropTypes from 'prop-types';

const HEIGHT = Dimensions.get('screen').height,
  WIDTH = Dimensions.get('screen').width,
  beforePostion = {
    center: 0.5,
    bottom: 0.85,
    top: 0.1,
  };
export default class Toast extends Component {
  /**
   * message: 要提示的信息
   * position: 提示信息在屏幕中的位置(x,y)
   *  - top 上方 居中
   *  - center 居中 居中
   *  - bottom 下方 居中
   */
  static defaultProps = {
    message: '',
    position: 'center',
  };
  static propTypes = {
    message: PropTypes.string,
    position: PropTypes.string,
  };
  constructor(props) {
    super(props);
    this.state = {
      fade: new Animated.Value(0),
    };
  }
  /**
   * 關閉toast
   */
  closeToast() {
    // this.state.fade.se
    Animated.timing(this.state.fade, {
      toValue: 0,
      duration: 500,
      useNativeDriver: true,
      easing: Easing.elastic(1),
    }).start();
  }
  /**
   * 顯示多少秒後關閉,一般調用這個
   * @param {Number} seconde
   */
  showAfterSecondClose(seconde) {
    this.showToast();
    setTimeout(() => {
      this.closeToast();
    }, seconde);
  }
  /**
   * 顯示toast
   */
  showToast() {
    Animated.timing(this.state.fade, {
      toValue: 1,
      duration: 500,
      useNativeDriver: true,
      easing: Easing.elastic(1),
    }).start();
  }
  render() {
    const messageLen = this.props.message.length,
      ToastWidth = messageLen * 18 + 20,
      positionLevel = beforePostion[this.props.position]
        ? beforePostion[this.props.position]
        : 0.5;
    return (
      <Animated.View
        style={[
          styles.wrap,
          {
            opacity: this.state.fade,
            top: HEIGHT * positionLevel - 20,
            transform: [
              {
                scale: this.state.fade,
                translateY: this.state.fade.interpolate({
                  inputRange: [0, 1],
                  outputRange: [0, -20],
                }),
              },
            ],
          },
        ]}>
        <Animated.Text ref="message" style={styles.wrapText}>
          {this.props.message}
        </Animated.Text>
        {/* </View> */}
      </Animated.View>
    );
  }
}

const styles = StyleSheet.create({
  wrap: {
    position: 'absolute',
    justifyContent: 'center',
    alignItems: 'center',
    width: WIDTH,
    zIndex: 999,
    elevation: 999,
  },
  wrapText: {
    color: '#fff',
    fontSize: 18,
    padding: 10,
    backgroundColor: '#000',
    borderRadius: 5,
    fontWeight: 'bold',
  },
});

注意:

  • Toast 組件不能顯示在最上方,就需要設置zIndexelevation 兩個樣式屬性
    • zIndex :在 Android 中無效,但在 IOS 中有效
    • elevation :在 Android 中有效,但在 IOS 中無效
  • 其他的感覺就沒什麼了,學習 Animated 可以看官網的文檔,寫的還是比較詳細的

使用

大家也看到了,我想外暴露了兩個屬性可以進行傳遞

  • message:要提示的信息
  • position:提示信息在屏幕中的位置
import React, {Component} from 'react';
import {View, Button} from 'react-native';

import Toast from '../../components/Toast';

export default class MyPage extends Component {
  render() {
    return (
      <View>
        <Button
          title="顯示Toast"
          onPress={() => {
            this.refs.toast.showToast();
          }}
        />
        <Button
          title="關閉Toast"
          onPress={() => {
            this.refs.toast.closeToast();
          }}
        />
        <Button
          title="2秒後消失"
          onPress={() => {
            this.refs.toast.showAfterSecondClose(2);
          }}
        />
        <Toast ref="toast" message={'顯示以下Toast'} />
      </View>
    );
  }
}

效果圖:
在這裏插入圖片描述

自己封裝個組件感覺還是很爽的

參考資料

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