英文:
How can I prevent two sounds from playing simultaneously?
问题
在我的应用中,我有两个可按的地方,如果你按其中一个,它会播放相应的声音。当然,如果你按另一个,它也会播放相应的声音。
但是我想要这样的效果:当一个声音正在播放时,如果我按另一个,先前的声音将停止播放,而不是同时播放两个声音,我该怎么做?
这是我的代码。
这两个是可按的:
<SoundPlayer voice={route.params.voice}>
<English English={route.params.English} />
</SoundPlayer>
<SoundPlayer voice={route.params.voice2}>
<NoteDesc noteDesc={route.params.noteDesc} />
</SoundPlayer>
这是用于播放声音的部分:
import React, { useEffect, useState } from "react";
import {
Button,
Text,
TouchableWithoutFeedback,
TouchableOpacity,
StyleSheet,
View,
} from "react-native";
import { Audio } from "expo-av";
export default function SoundPlayer({ voice, children }) {
const [sound, setSound] = useState();
async function playSound() {
console.log("Loading Sound");
if (sound) {
console.log("Unloading Sound");
await sound.unloadAsync();
}
const { sound: newSound } = await Audio.Sound.createAsync(voice);
setSound(newSound);
console.log("Playing Sound");
await newSound.playAsync();
}
useEffect(() => {
return sound
? () => {
console.log("Unloading Sound");
sound.unloadAsync();
}
: undefined;
}, [sound]);
return (
<View>
<TouchableOpacity onPress={playSound}>{children}</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {},
English: {
color: "snow",
fontSize: 30,
textAlign: "center",
},
});
提前感谢你。
英文:
In my app, I have two pressable places, and if you press one of them, it plays the corresponding sound.
And, if you press the other one, of course, it plays the corresponding sound.
But I want something like this: when one is being played, if I press the other one, the previous one will be stopped playing, rather than playing two of them at the same time, how can I do that?
Here is my code.
These two are pressable:
<SoundPlayer voice={route.params.voice}>
<English English={route.params.English} />
</SoundPlayer>
<SoundPlayer voice={route.params.voice2}>
<NoteDesc noteDesc={route.params.noteDesc} />
</SoundPlayer>
This is for playing sounds:
import React, { useEffect, useState } from "react";
import {
Button,
Text,
TouchableWithoutFeedback,
TouchableOpacity,
StyleSheet,
View,
} from "react-native";
import { Audio } from "expo-av";
export default function SoundPlayer({ voice, children }) {
const [sound, setSound] = useState();
async function playSound() {
console.log("Loading Sound");
if (sound) {
console.log("Unloading Sound");
await sound.unloadAsync();
}
const { sound: newSound } = await Audio.Sound.createAsync(voice);
setSound(newSound);
console.log("Playing Sound");
await newSound.playAsync();
}
useEffect(() => {
return sound
? () => {
console.log("Unloading Sound");
sound.unloadAsync();
}
: undefined;
}, [sound]);
return (
<View>
<TouchableOpacity onPress={playSound}>{children}</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {},
English: {
color: "snow",
fontSize: 30,
textAlign: "center",
},
});
Thank you in advance.
答案1
得分: 1
You have this sound
state in SoundPlayer
. It will be unique to each <SoundPlayer />
call. So at this point, whenever playSound
is called, sound
refers only to the current component's playing sound.
I would suggest you move this const [sound, setSound] = useState()
in an outer parent component, for example with the Context API. Something like this:
// SoundContextProvider.js
import { useState, createContext, useContext } from "react";
const SoundContext = createContext();
export default function SoundContextProvider({ children }) {
const [sound, setSound] = useState();
return <SoundContext.Provider value={{ sound, setSound }}>{children}</SoundContext.Provider>;
}
export function useSoundContext() {
return useContext(SoundContext);
}
Grab it inside SoundPlayer
like below. This way you are always referring to the same sound
instance:
import { useSoundContext } from "./SoundContextProvider"; // Make sure you use the correct path.
export default function SoundPlayer({ voice, children }) {
const { sound, setSound } = useSoundContext();
// ...
}
Finally, ensure, for example, in App.js
, you render your components wrapped by SoundContextProvider
:
import SoundContextProvider from "./SoundContextProvider"; // Make sure you use the correct path.
export default function App() {
// ...
return <SoundContextProvider>{/* Your components go here*/}</SoundContextProvider>;
}
英文:
You have this sound
state in SoundPlayer
. It will be unique to each <SoundPlayer />
call. So at this point, whenever playSound
is called, sound
refers only to the current component's playing sound.
I would suggest you move this const [sound, setSound] = useState()
in an outer parent component, for example with the Context API. Something like this:
// SoundContextProvider.js
import { useState, createContext, useContext } from "react";
const SoundContext = createContext();
export default function SoundContextProvider({ children }) {
const [sound, setSound] = useState();
return <SoundContext.Provider value={{ sound, setSound }}>{children}</SoundContext.Provider>;
}
export function useSoundContext() {
return useContext(SoundContext);
}
Grab it inside SoundPlayer
like below. This way you are always referring to the same sound
instance:
import { useSoundContext } from "./SoundContextProvider"; // Make sure you use the correct path.
export default function SoundPlayer({ voice, children }) {
const { sound, setSound } = useSoundContext();
// ...
}
Finally, ensure, for example, in App.js
, you render your components wrapped by SoundContextProvider
:
import SoundContextProvider from "./SoundContextProvider"; // Make sure you use the correct path.
export default function App() {
// ...
return <SoundContextProvider>{/* Your components goe here*/}</SoundContextProvider>;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论