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

Flutter使用audio_query/just_audio跨页传歌曲列表实现切歌

问题根因
  • 歌曲列表无法跨页传递:跳转路由时仅传入了当前点击的单首SongModel实例,没有将查询得到的完整歌曲列表作为路由参数传入播放页。
  • 上下首切歌失效:just_audio的seekToPrevious、seekToNext、hasPrevious、hasNext系列方法仅在播放器加载**队列式音频源(ConcatenatingAudioSource)**时生效,原有逻辑只加载了单首歌曲的音频源,播放器无队列上下文,无法识别前后曲目。
修复方案

1. 调整歌曲列表页代码

首先将查询到的歌曲列表存入页面状态,跳转时传入完整列表、当前点击索引,同时初始化播放队列替代原有单首加载逻辑:

// 在列表页对应的State类中声明状态变量
List<SongModel> songList = [];
// 保留你原有的audioPlayer实例
final AudioPlayer audioPlayer = AudioPlayer();

// 修改原有FutureBuilder逻辑
body: FutureBuilder<List<SongModel>>(
  future: audioQuery.querySongs(),
  builder: (context, snapshot) {
    if (snapshot.data == null) {
      return const Center(child: CircularProgressIndicator());
    }
    if (snapshot.data!.isEmpty) {
      return const Center(child: Text('No data found'));
    }
    // 将查询结果存入状态变量
    songList = snapshot.data!;

    return ListView.builder(
      itemCount: songList.length,
      itemBuilder: (context, index) {
        return ListTile(
          onTap: () async {
            // 替换原有单首播放逻辑,构建全量歌曲播放队列
            final audioPlaylist = ConcatenatingAudioSource(
              children: songList.map((song) => 
                AudioSource.uri(Uri.parse(song.uri))
              ).toList(),
            );
            // 加载队列,设置初始播放位置为当前点击的歌曲索引
            await audioPlayer.load(audioPlaylist);
            await audioPlayer.seek(Duration.zero, index: index);
            audioPlayer.play();

            // 跳转时传入全部所需参数
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => PlayerView(
                  songList: songList, // 传入完整歌曲列表
                  initialIndex: index, // 传入初始播放索引
                  songModel: songList[index],
                  audioPlayer: audioPlayer,
                ),
              ),
            );
          },
          // 原有ListTile的标题、副标题、封面等布局代码保持不变
        );
      },
    );
  },
)

2. 修改播放页PlayerView的构造函数

新增参数接收传入的完整歌曲列表和初始索引:

class PlayerView extends StatefulWidget {
  // 原有参数
  final SongModel songModel;
  final AudioPlayer audioPlayer;
  // 新增参数
  final List<SongModel> songList;
  final int initialIndex;

  const PlayerView({
    super.key,
    required this.songModel,
    required this.audioPlayer,
    required this.songList,
    required this.initialIndex,
  });

  @override
  State<PlayerView> createState() => _PlayerViewState();
}

3. 切歌逻辑适配

原有上一首、下一首按钮的核心逻辑无需修改,播放器加载队列资源后会自动识别前后曲边界,点击即可正常触发切歌。

如果需要切歌时同步更新播放页显示的歌曲名、封面、艺术家等信息,只需监听audioPlayer.currentIndexStream流,在索引变化时从widget.songList中取对应索引的SongModel数据,通过setState更新页面即可。


内容的提问来源于stack exchange,提问作者2Shotezz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:27:24