You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React Native Expo中使用expo-av库消除TouchableOpacity点击音效延迟的解决方案

React Native Expo中使用expo-av库消除TouchableOpacity点击音效延迟的解决方案

嘿,我完全懂你这种闹心的感受——点击按钮后音效慢半拍,简直破坏了交互的流畅感!咱们来一步步搞定这个问题:

问题根源分析

你当前的代码里,每次点击按钮都会调用playsoundone(),而这个函数每次都重新执行Audio.Sound.createAsync来创建新的音效实例。这个异步操作需要加载本地音频文件、初始化音效资源,这就是那1秒延迟的核心原因!

核心解决方案:提前预加载音效

正确的做法是在组件挂载时就把音效加载好,存在状态里,点击时直接调用预加载完成的音效实例来播放,避免每次点击都重复初始化。

具体实现步骤

  1. 使用useState存储预加载好的音效实例
  2. useEffect中完成音效的预加载,组件卸载时记得释放资源(避免内存泄漏)
  3. 点击按钮时直接调用预加载实例的播放方法

完整代码示例

import React, { useState, useEffect } from 'react';
import { TouchableOpacity, Text } from 'react-native';
import { Audio } from 'expo-av';

const SoundButton = () => {
  // 存储预加载的音效实例
  const [soundOne, setSoundOne] = useState(null);

  useEffect(() => {
    // 组件挂载时预加载音效
    const loadSound = async () => {
      const { sound } = await Audio.Sound.createAsync(
        require('../../assets/music/noteone.aac')
      );
      setSoundOne(sound);
    };

    loadSound();

    // 组件卸载时释放音效资源
    return () => {
      if (soundOne) {
        soundOne.unloadAsync();
      }
    };
  }, []);

  // 点击时播放预加载好的音效
  const playSoundOne = async () => {
    if (!soundOne) return;
    // 先重置到音效开头,避免重复点击时只播放剩余部分
    await soundOne.replayAsync();
  };

  return (
    <TouchableOpacity onPressIn={playSoundOne}>
      <Text style={{ color: 'white', fontSize: 80 }}>Tap</Text>
    </TouchableOpacity>
  );
};

export default SoundButton;

额外优化建议

  • 音频文件优化:虽然你已经调整了比特率,还可以尝试将音频裁剪到最短必要长度,采样率设置为44.1kHz(移动端常用的高效采样率)
  • 音频模式配置:可以在初始化时设置合适的音频模式,确保音效优先级:
    // 在loadSound函数开头添加
    await Audio.setAudioModeAsync({
      allowsRecordingIOS: false,
      playsInSilentModeIOS: true,
      shouldDuckAndroid: true,
      staysActiveInBackground: false,
    });
    
  • 避免主线程阻塞:检查点击时是否有其他同步/异步任务在执行,比如状态更新、网络请求等,这些可能会延迟音效播放

备注:内容来源于stack exchange,提问作者Libin Rockey Jacob

火山引擎 最新活动