如何在同一页面中播放多个音频文件?
How to play more than one audio file in the same page in flutter?
我有一个聊天页面,用户可以在其中将文本、图像、音频和视频作为消息发送给其他用户。除了音频和视频,一切正常。在我的聊天应用程序中,允许用户使用 file_picker 插件选择音频文件。用户选择音频文件后,将其上传到服务器。然后服务器使用套接字事件发回音频文件。我的应用程序侦听套接字事件并根据消息类型生成消息视图。如果是文本消息,则会显示在文本小部件中。如果是音频消息,则会显示在音频小部件中。 audio_player 插件用于播放音频文件。当用户上传音频时,稍后会向在同一房间聊天的两个用户显示音频文件。如果它是单个音频文件,一切正常。如果用户上传另一个音频文件,如第二个音频,音频控制器会用上次上传的音频替换聊天视图中我的所有音频文件。用于音频的代码如下:
//for audio files (This code has been placed in _ChatPageState)
AnimationController _animationIconController1;
AudioCache audioCache;
AudioPlayer audioPlayer;
Duration _duration = new Duration();
Duration _position = new Duration();
Duration _slider = new Duration(seconds: 0);
double durationValue;
bool isSongPlaying = false;
bool isPlaying = false;
稍后,变量在initState()中被初始化
//for audio inside initState
_position = _slider;
_animationIconController1 = AnimationController(
vsync: this,
duration: Duration(milliseconds: 750),
reverseDuration: Duration(milliseconds: 750),
);
audioPlayer = new AudioPlayer();
audioCache = new AudioCache(fixedPlayer: audioPlayer);
audioPlayer.durationHandler = (d) => setState(() {
_duration = d;
});
audioPlayer.positionHandler = (p) => setState(() {
_position = p;
});
接下来,如果用户从套接字侦听器接收到音频文件,则会显示一个音频小部件,以便用户可以播放该文件:
Widget audioMessage(int index) {
return Container(
width: MediaQuery.of(context).size.width * 0.6,
height: 30,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
setState(() {
isPlaying ? _animationIconController1.reverse() : _animationIconController1.forward();
isPlaying = !isPlaying;
});
// Add code to pause and play the music.
if (!isSongPlaying){
audioPlayer.play('some hidden link/file/${messages[index].message}');
setState(() {
isSongPlaying = true;
});
} else {
audioPlayer.pause();
setState(() {
isSongPlaying = false;
});
}
},
child: ClipOval(
child: Container(
color: Colors.pink[600],
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AnimatedIcon(
icon: isSongPlaying ==false ? AnimatedIcons.play_pause : AnimatedIcons.pause_play,
size: 14,
progress: _animationIconController1,
color: Colors.white,
),
),
),
),
),
Slider(
activeColor: Colors.white,
inactiveColor: Colors.grey,
value: _position.inSeconds.toDouble(),
max: _duration.inSeconds.toDouble(),
onChanged: (double value) {
seekToSeconds(value.toInt());
value = value;
},
),
],
),
);
}
我认为问题出在我的音频和动画控制器上。它只为一名玩家发起。那么我该如何解决这个问题。用户可以上传任意数量的音频。我如何为用户上传的尽可能多的音频文件动态创建音频控制器?
因此,我通过将所有音频代码移动到一个单独的 dart 文件中来完成此操作。请参阅下面的音频实现:
class PlayAudio extends StatefulWidget {
final String url;
const PlayAudio({Key key, this.url}) : super(key: key);
@override
_PlayAudioState createState() => _PlayAudioState();
}
class _PlayAudioState extends State<PlayAudio> with TickerProviderStateMixin{
//for audio files
AnimationController _animationIconController1;
AudioCache audioCache;
AudioPlayer audioPlayer;
Duration _duration = new Duration();
Duration _position = new Duration();
Duration _slider = new Duration(seconds: 0);
double durationValue;
bool isSongPlaying = false;
bool isPlaying = false;
@override
void initState() {
// TODO: implement initState
super.initState();
//for audio inside initState
_position = _slider;
_animationIconController1 = new AnimationController(
vsync: this,
duration: new Duration(milliseconds: 750),
reverseDuration: new Duration(milliseconds: 750),
);
audioPlayer = new AudioPlayer();
audioCache = new AudioCache(fixedPlayer: audioPlayer);
audioPlayer.durationHandler = (d) => setState(() {
_duration = d;
});
audioPlayer.positionHandler = (p) => setState(() {
_position = p;
});
print('audio widget: ' + widget.url);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
audioPlayer.dispose();
}
void seekToSeconds(int second) {
Duration newDuration = Duration(seconds: second);
audioPlayer.seek(newDuration);
}
@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width * 0.6,
height: 30,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
setState(() {
isPlaying ? _animationIconController1.reverse() : _animationIconController1.forward();
isPlaying = !isPlaying;
});
// Add code to pause and play the music.
if (!isSongPlaying){
audioPlayer.play('${widget.url}');
setState(() {
isSongPlaying = true;
});
} else {
audioPlayer.pause();
setState(() {
isSongPlaying = false;
});
}
},
child: ClipOval(
child: Container(
color: Colors.pink[600],
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AnimatedIcon(
icon: AnimatedIcons.play_pause,
size: 14,
progress: _animationIconController1,
color: Colors.white,
),
),
),
),
),
Slider(
activeColor: Colors.white,
inactiveColor: Colors.grey,
value: _position.inSeconds.toDouble(),
max: _duration.inSeconds.toDouble(),
onChanged: (double value) {
seekToSeconds(value.toInt());
value = value;
},
),
],
),
);
}
}
现在这是一个单独的 class。现在,要播放多个音频文件,我所做的就是在需要的地方将上述文件调用到我的 main.dart 中。确保每次要播放新音频文件时都调用 'new',只需传递一个 url。见下文:
new PlayAudio(url: 'some URL');
希望这有助于在同一页面中播放多个音频文件。仅供参考,我正在使用 https://pub.dev/packages/audioplayers
我有一个聊天页面,用户可以在其中将文本、图像、音频和视频作为消息发送给其他用户。除了音频和视频,一切正常。在我的聊天应用程序中,允许用户使用 file_picker 插件选择音频文件。用户选择音频文件后,将其上传到服务器。然后服务器使用套接字事件发回音频文件。我的应用程序侦听套接字事件并根据消息类型生成消息视图。如果是文本消息,则会显示在文本小部件中。如果是音频消息,则会显示在音频小部件中。 audio_player 插件用于播放音频文件。当用户上传音频时,稍后会向在同一房间聊天的两个用户显示音频文件。如果它是单个音频文件,一切正常。如果用户上传另一个音频文件,如第二个音频,音频控制器会用上次上传的音频替换聊天视图中我的所有音频文件。用于音频的代码如下:
//for audio files (This code has been placed in _ChatPageState)
AnimationController _animationIconController1;
AudioCache audioCache;
AudioPlayer audioPlayer;
Duration _duration = new Duration();
Duration _position = new Duration();
Duration _slider = new Duration(seconds: 0);
double durationValue;
bool isSongPlaying = false;
bool isPlaying = false;
稍后,变量在initState()中被初始化
//for audio inside initState
_position = _slider;
_animationIconController1 = AnimationController(
vsync: this,
duration: Duration(milliseconds: 750),
reverseDuration: Duration(milliseconds: 750),
);
audioPlayer = new AudioPlayer();
audioCache = new AudioCache(fixedPlayer: audioPlayer);
audioPlayer.durationHandler = (d) => setState(() {
_duration = d;
});
audioPlayer.positionHandler = (p) => setState(() {
_position = p;
});
接下来,如果用户从套接字侦听器接收到音频文件,则会显示一个音频小部件,以便用户可以播放该文件:
Widget audioMessage(int index) {
return Container(
width: MediaQuery.of(context).size.width * 0.6,
height: 30,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
setState(() {
isPlaying ? _animationIconController1.reverse() : _animationIconController1.forward();
isPlaying = !isPlaying;
});
// Add code to pause and play the music.
if (!isSongPlaying){
audioPlayer.play('some hidden link/file/${messages[index].message}');
setState(() {
isSongPlaying = true;
});
} else {
audioPlayer.pause();
setState(() {
isSongPlaying = false;
});
}
},
child: ClipOval(
child: Container(
color: Colors.pink[600],
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AnimatedIcon(
icon: isSongPlaying ==false ? AnimatedIcons.play_pause : AnimatedIcons.pause_play,
size: 14,
progress: _animationIconController1,
color: Colors.white,
),
),
),
),
),
Slider(
activeColor: Colors.white,
inactiveColor: Colors.grey,
value: _position.inSeconds.toDouble(),
max: _duration.inSeconds.toDouble(),
onChanged: (double value) {
seekToSeconds(value.toInt());
value = value;
},
),
],
),
);
}
我认为问题出在我的音频和动画控制器上。它只为一名玩家发起。那么我该如何解决这个问题。用户可以上传任意数量的音频。我如何为用户上传的尽可能多的音频文件动态创建音频控制器?
因此,我通过将所有音频代码移动到一个单独的 dart 文件中来完成此操作。请参阅下面的音频实现:
class PlayAudio extends StatefulWidget {
final String url;
const PlayAudio({Key key, this.url}) : super(key: key);
@override
_PlayAudioState createState() => _PlayAudioState();
}
class _PlayAudioState extends State<PlayAudio> with TickerProviderStateMixin{
//for audio files
AnimationController _animationIconController1;
AudioCache audioCache;
AudioPlayer audioPlayer;
Duration _duration = new Duration();
Duration _position = new Duration();
Duration _slider = new Duration(seconds: 0);
double durationValue;
bool isSongPlaying = false;
bool isPlaying = false;
@override
void initState() {
// TODO: implement initState
super.initState();
//for audio inside initState
_position = _slider;
_animationIconController1 = new AnimationController(
vsync: this,
duration: new Duration(milliseconds: 750),
reverseDuration: new Duration(milliseconds: 750),
);
audioPlayer = new AudioPlayer();
audioCache = new AudioCache(fixedPlayer: audioPlayer);
audioPlayer.durationHandler = (d) => setState(() {
_duration = d;
});
audioPlayer.positionHandler = (p) => setState(() {
_position = p;
});
print('audio widget: ' + widget.url);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
audioPlayer.dispose();
}
void seekToSeconds(int second) {
Duration newDuration = Duration(seconds: second);
audioPlayer.seek(newDuration);
}
@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width * 0.6,
height: 30,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
setState(() {
isPlaying ? _animationIconController1.reverse() : _animationIconController1.forward();
isPlaying = !isPlaying;
});
// Add code to pause and play the music.
if (!isSongPlaying){
audioPlayer.play('${widget.url}');
setState(() {
isSongPlaying = true;
});
} else {
audioPlayer.pause();
setState(() {
isSongPlaying = false;
});
}
},
child: ClipOval(
child: Container(
color: Colors.pink[600],
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AnimatedIcon(
icon: AnimatedIcons.play_pause,
size: 14,
progress: _animationIconController1,
color: Colors.white,
),
),
),
),
),
Slider(
activeColor: Colors.white,
inactiveColor: Colors.grey,
value: _position.inSeconds.toDouble(),
max: _duration.inSeconds.toDouble(),
onChanged: (double value) {
seekToSeconds(value.toInt());
value = value;
},
),
],
),
);
}
}
现在这是一个单独的 class。现在,要播放多个音频文件,我所做的就是在需要的地方将上述文件调用到我的 main.dart 中。确保每次要播放新音频文件时都调用 'new',只需传递一个 url。见下文:
new PlayAudio(url: 'some URL');
希望这有助于在同一页面中播放多个音频文件。仅供参考,我正在使用 https://pub.dev/packages/audioplayers