You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为react-native-toast-message添加自动隐藏倒计时进度条?

为react-native-toast-message添加自动隐藏进度条的实现方案

问题描述

我希望为react-native-toast-message添加一个状态进度条,用于提示Toast消息何时自动隐藏。但在官方文档中未找到相关配置,想了解基于该库的可行实现方案。

当前代码(App.tsx)

import React from 'react';
import * as SplashScreen from 'expo-splash-screen';
import { Button, Pressable, Text, View } from 'react-native';
import Toast from 'react-native-toast-message';
import { AntDesign, Ionicons as Icon } from '@expo/vector-icons';

// Keep the splash screen visible while we fetch resources
SplashScreen.preventAutoHideAsync();

const toastConfig = {
  success: ({ text1 }: any) => (
    <View
      style={{
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'center',
        height: 60,
        width: '100%',
        paddingLeft: 20,
        backgroundColor: '#87b64f'
      }}
    >
      <Text style={{ color: '#ffffff', fontSize: 20 }}>
        {text1}
        <Icon name="checkmark" size={24} color="#ffffff" />
      </Text>
      <Pressable
        style={{
          justifyContent: 'center',
          alignItems: 'center',
          width: 60,
          height: '100%',
          marginLeft: 'auto',
          borderLeftWidth: 1,
          borderColor: '#ffffff'
        }}
        onPress={() => Toast.hide()}
      >
        <AntDesign name="close" size={24} color="#ffffff" />
      </Pressable>
    </View>
  ),
  error: ({ text1 }: any) => (
    <View
      style={{
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'center',
        height: 60,
        width: '100%',
        paddingLeft: 20,
        backgroundColor: '#f27474'
      }}
    >
      <Text style={{ color: '#ffffff', fontSize: 20 }}>{text1}</Text>
      <Pressable
        style={{
          justifyContent: 'center',
          alignItems: 'center',
          width: 60,
          height: '100%',
          marginLeft: 'auto',
          borderLeftWidth: 1,
          borderColor: '#ffffff'
        }}
        onPress={() => Toast.hide()}
      >
        <AntDesign name="close" size={24} color="#ffffff" />
      </Pressable>
    </View>
  )
};

export default function App(): JSX.Element {
  return (
    <View
      style={{ display: 'flex', paddingTop: 200, paddingHorizontal: 40, backgroundColor: '#ffffff', height: '100%' }}
    >
      <Button
        title="Show Toast"
        onPress={() =>
          Toast.show({
            topOffset: 0,
            type: 'success',
            text1: 'Success'
          })
        }
      />
      <Toast config={toastConfig} />
    </View>
  );
}

效果对比

预期效果

预期效果示意图

当前效果

当前效果示意图

实现方案

由于react-native-toast-message官方未提供进度条配置,我们可以通过自定义Toast组件+动画进度条实现,核心是用Animated API绑定Toast显示时长做进度动画:

改造后的完整代码

import React, { useEffect, useRef } from 'react';
import { Button, Pressable, Text, View, Animated } from 'react-native';
import Toast from 'react-native-toast-message';
import { AntDesign, Ionicons as Icon } from '@expo/vector-icons';
import * as SplashScreen from 'expo-splash-screen';

SplashScreen.preventAutoHideAsync();

// 带进度条的自定义Toast组件
const ProgressToast = ({ text1, type, onHide }: { text1: string, type: 'success' | 'error', onHide: () => void }) => {
  const displayDuration = 3000; // 与Toast.show的duration保持一致
  const progressAnim = useRef(new Animated.Value(1)).current;

  useEffect(() => {
    // 启动进度条动画:从100%宽度缩至0
    const timer = Animated.timing(progressAnim, {
      toValue: 0,
      duration: displayDuration,
      useNativeDriver: false,
    }).start(() => onHide()); // 动画结束后触发隐藏

    return () => timer.stop(); // 组件卸载时终止动画
  }, [progressAnim, displayDuration, onHide]);

  // 插值转换进度条宽度
  const progressWidth = progressAnim.interpolate({
    inputRange: [0, 1],
    outputRange: ['0%', '100%'],
  });

  const [bgColor, progressBgColor] = type === 'success' 
    ? ['#87b64f', '#6a993d'] 
    : ['#f27474', '#d9534f'];

  return (
    <View style={{ width: '100%' }}>
      <View
        style={{
          flexDirection: 'row',
          alignItems: 'center',
          height: 60,
          paddingLeft: 20,
          backgroundColor: bgColor,
        }}
      >
        <Text style={{ color: '#fff', fontSize: 20, flex: 1 }}>
          {text1}
          {type === 'success' && <Icon name="checkmark" size={24} color="#fff" style={{ marginLeft: 8 }} />}
        </Text>
        <Pressable
          style={{
            justifyContent: 'center',
            alignItems: 'center',
            width: 60,
            height: '100%',
            borderLeftWidth: 1,
            borderColor: '#fff',
          }}
          onPress={onHide}
        >
          <AntDesign name="close" size={24} color="#fff" />
        </Pressable>
      </View>
      {/* 底部进度条容器 */}
      <View style={{ height: 3, backgroundColor: 'rgba(255,255,255,0.3)' }}>
        <Animated.View style={{ height: '100%', width: progressWidth, backgroundColor: progressBgColor }} />
      </View>
    </View>
  );
};

const toastConfig = {
  success: ({ text1, onHide }: any) => (
    <ProgressToast text1={text1} type="success" onHide={onHide} />
  ),
  error: ({ text1, onHide }: any) => (
    <ProgressToast text1={text1} type="error" onHide={onHide} />
  ),
};

export default function App(): JSX.Element {
  return (
    <View
      style={{ flex: 1, paddingTop: 200, paddingHorizontal: 40, backgroundColor: '#fff' }}
    >
      <Button
        title="Show Toast"
        onPress={() =>
          Toast.show({
            topOffset: 0,
            type: 'success',
            text1: 'Success',
            duration: 3000, // 必须和ProgressToast的displayDuration一致
          })
        }
      />
      <Toast config={toastConfig} />
    </View>
  );
}

关键注意点

  • 进度条动画时长必须与Toast.show中的duration参数完全一致,保证进度走完时Toast刚好隐藏;
  • 点击关闭按钮时,动画会自动终止并触发隐藏,避免内存泄漏;
  • 通过type参数区分success/error样式,保持原有设计风格;
  • 进度条使用半透明底色+深色进度条,既不干扰主内容,又能清晰提示剩余时长。

内容的提问来源于stack exchange,提问作者Fiddle Freak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 15:35:56