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

Flutter中使用audioplayers包拖动滑块Seek后音频停止无法恢复的问题求助

Flutter中使用audioplayers包拖动滑块Seek后音频停止无法恢复的问题求助

我仔细看了你的代码,发现几个可能导致问题的点,下面给出修复方案和原因解析:

问题根源分析

  1. 音频初始化的异步问题:你在initState里直接调用audioPlayer.setSourceAsset,但这个方法是异步的,可能音频还没完全加载就进行seek操作,导致状态异常。
  2. Seek后的状态判断缺失:当你拖动滑块时,没有记录之前的播放状态,直接调用resume()可能因为播放器状态不是paused而失效。
  3. 滑块的可用性控制:当duration还未加载完成时(初始为Duration.zero),滑块的max设为1,此时拖动滑块可能会seek到无效位置,导致音频停止。

修复后的完整代码

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';

class AudioPlayerScreen extends StatefulWidget {
  @override
  _AudioPlayerScreenState createState() => _AudioPlayerScreenState();
}

class _AudioPlayerScreenState extends State<AudioPlayerScreen> {
  Duration duration = Duration.zero;
  Duration position = Duration.zero;
  final AudioPlayer audioPlayer = AudioPlayer();
  bool isPlaying = false;
  bool isAudioLoaded = false; // 新增:标记音频是否加载完成

  @override
  void initState() {
    super.initState();
    _initAudioPlayer(); // 改为异步初始化方法
  }

  // 异步初始化音频播放器,确保音频加载完成后再设置监听
  Future<void> _initAudioPlayer() async {
    try {
      await audioPlayer.setSourceAsset('audio/music.mp3');
      setState(() {
        isAudioLoaded = true;
      });
      // 设置状态监听
      audioPlayer.onPlayerStateChanged.listen((PlayerState state) {
        setState(() {
          isPlaying = state == PlayerState.playing;
        });
      });
      audioPlayer.onDurationChanged.listen((Duration d) {
        setState(() {
          duration = d;
        });
      });
      audioPlayer.onPositionChanged.listen((Duration p) {
        setState(() {
          position = p;
        });
      });
    } catch (e) {
      print('音频加载失败: $e');
    }
  }

  @override
  void dispose() {
    audioPlayer.dispose();
    super.dispose();
  }

  Future<void> togglePlayPause() async {
    if (isPlaying) {
      await audioPlayer.pause();
    } else {
      // 如果是第一次播放或者seek后,用play而不是resume更可靠
      await audioPlayer.play(AssetSource('audio/music.mp3'), position: position);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Audio Player'),
        centerTitle: true,
      ),
      body: Padding(
        padding: const EdgeInsets.all(24.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 音频未加载时禁用滑块,避免无效操作
            Slider(
              enabled: isAudioLoaded && duration.inSeconds > 0,
              value: position.inSeconds.toDouble().clamp(0, duration.inSeconds.toDouble()),
              min: 0,
              max: duration.inSeconds.toDouble(),
              activeColor: Colors.amber,
              onChanged: (double value) async {
                final newPosition = Duration(seconds: value.toInt());
                // 记录当前播放状态
                final wasPlaying = isPlaying;
                // 先seek到目标位置
                await audioPlayer.seek(newPosition);
                // 如果之前在播放,就恢复播放
                if (wasPlaying) {
                  await audioPlayer.play(AssetSource('audio/music.mp3'), position: newPosition);
                }
                // 更新position状态
                setState(() {
                  position = newPosition;
                });
              },
            ),
            IconButton(
              icon: Icon(isPlaying ? Icons.pause_circle : Icons.play_arrow),
              iconSize: 64,
              onPressed: togglePlayPause,
            ),
          ],
        ),
      ),
    );
  }
}

关键修复点说明

  1. 异步初始化音频:把音频加载逻辑放到单独的异步方法_initAudioPlayer中,确保音频完全加载后再启用滑块和设置监听,避免未加载完成时的无效操作。
  2. 记录播放状态再恢复:在seek前记录当前是否在播放,seek完成后如果之前是播放状态,直接调用play并传入目标位置,比resume更可靠,因为某些情况下seek后播放器状态可能变为stopped,resume无法触发播放。
  3. 控制滑块可用性:新增isAudioLoaded标记,音频未加载或duration未获取时禁用滑块,防止用户拖动到无效位置导致音频异常。
  4. 合并播放暂停逻辑:把播放和暂停的逻辑合并到togglePlayPause方法中,统一处理第一次播放、暂停恢复、seek后的播放场景,代码更简洁。

这样修改后,应该就能正常拖动滑块seek并恢复播放了,你可以试试这个方案。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 03:10:46