带有音频播放器的Flutter Bloc

时间:2019-08-27 13:39:22

标签: flutter dart

几乎每天都在想办法,我需要您的帮助。

我创建了一个应用,该应用的状态为audioplayers,并使用flutter_bloc

问题:

  1. 状态播放器会播放,但是小部件MusicPlayer不会使用BlocBuilder重建小部件
  2. 我还尝试从正在播放的音乐中获取currentPositionduration,并使用LinearPercentIndicator包中的linear_percent_indicator进行显示,但似乎无法找到一个解决方案,因为重建无法正常工作。
  3. 我想念什么?

这是我到目前为止所拥有的:

集团

class AudioPlayerBloc extends Bloc<AudioPlayerEvents, MusicPlayerState> {
  @override
  MusicPlayerState get initialState => MusicPlayerState(
        player: AudioPlayer(),
        episode: Episode(),
      );

  @override
  Stream<MusicPlayerState> mapEventToState(AudioPlayerEvents event) async* {
    if (event is InitializePlayer) {
      this.currentState.episode = event.episode;
      this.dispatch(PlayPlayer());
      yield this.currentState;
    }

    if (event is PlayPlayer) {
      this.play(this.currentState.episode.source);
    }

    if (event is PlayRemote) {
      this.currentState.player.stop();

      this.currentState.player.play(event.remoteURL);
      yield this.currentState;
    }

    if (event is ShowPlayer) {
      yield this.currentState;
    }

    if (event is HidePlayer) {
      yield this.currentState;
    }
  }

  void play(String remoteURL) {
    this.dispatch(PlayRemote(remoteURL));
  }

  void stop() async {
    await this.currentState.player.stop();
  }

  void pause() async{
    await this.currentState.player.pause();
  }

  void resume(){
    this.currentState.player.resume();
  }

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

事件

abstract class AudioPlayerEvents {}

class InitializePlayer extends AudioPlayerEvents {
  Episode episode;

  InitializePlayer(this.episode);
}

class PlayRemote extends AudioPlayerEvents {
  final String remoteURL;

  PlayRemote(this.remoteURL);
}

class PlayPlayer extends AudioPlayerEvents {}

class ShowPlayer extends AudioPlayerEvents {}

class HidePlayer extends AudioPlayerEvents {}

状态

import 'package:audioplayers/audioplayers.dart';

class MusicPlayerState {
  AudioPlayer player;
  Episode episode; // My Custom Class

  MusicPlayerState({
    this.player,
    this.episode,
  });
}

main.dart

@override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<AudioPlayerBloc>(
          builder: (_) => AudioPlayerBloc(),
        )
      ],
      child: MaterialApp(
        navigatorObservers: [],
        initialRoute: HomeScreen.id,
        routes: {
          HomeScreen.id: (context) => HomeScreen(app: widget.app),
        },
      ),
    );
  }
}

MusicPlayer.dart <-我的播放器小工具

class MusicPlayer extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    final AudioPlayerBloc audioPlayerBloc =
        BlocProvider.of<AudioPlayerBloc>(context);

    return BlocBuilder<AudioPlayerBloc, MusicPlayerState>(
      bloc: audioPlayerBloc,
      builder: (context, state) {
        return Container(
          height: 200.0,
          color: Colors.cyan[200],
          child: Padding(
            padding: const EdgeInsets.only(top: 20.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                Column(
                  children: <Widget>[
                    Text("${state.episode.name}"),
                    Row(
                      children: <Widget>[
                        Expanded(
                          flex: 1,
                          child: FutureBuilder<int>(
                            future: audioPlayerBloc.currentState.player.getCurrentPosition(),
                              builder: (context, AsyncSnapshot<int> snapshot) {
                                double seconds = snapshot.data / 1000;
                                if (snapshot.hasData) {
                                  return Text("${printDuration(Duration(seconds: seconds.toInt()), abbreviated: true)}");
                                } else {
                                  return Text('Calculating..');
                                }
                              },
                            ),
                        ),
                        Expanded(
                          flex: 3,
                          child: LinearPercentIndicator(
                            lineHeight: 7.0,
//                            percent: this.currentPosition / this.fileDuration,
                            percent: 0.3,
                            backgroundColor: Colors.grey,
                            progressColor: Colors.blue,
                          ),
                        ),
                        Expanded(
                          flex: 1,
                          child: FutureBuilder<int>(
                            future: audioPlayerBloc.currentState.player.getDuration(),
                            builder: (context, AsyncSnapshot<int> snapshot) {
                              double seconds = snapshot.data / 1000;
                              if (snapshot.hasData) {
                                return Text("${printDuration(Duration(seconds: seconds.toInt()), abbreviated: true)}");
                              } else {
                                return Text('Calculating..');
                              }
                            },
                          ),
                        ),
                      ],
                    ),
                    Text(state.player.state.toString()),
                    FlatButton(
                      onPressed: () {
                        print('close here');
                        Navigator.of(context).pop();
                      },
                      child: Icon(
                        Icons.close,
                        color: Colors.black.withOpacity(0.5),
                      ),
                    ),
                    Row(
                      children: <Widget>[
                        FlatButton(
                          onPressed: () {
                            audioPlayerBloc.pause();
                          },
                          child: Text('Pause Player'),
                        ),
                        FlatButton(
                          onPressed: () {
                            audioPlayerBloc.resume();
                          },
                          child: Text('Resume Player'),
                        ),
                        FlatButton(
                          onPressed: () {
                            audioPlayerBloc.stop();
                          },
                          child: Text('Stop Player'),
                        ),
                      ],
                    )
                  ],
                )
              ],
            ),
          ),
        );
      },
    );
  }
}

HomeScreen.dart <-我的第一个屏幕

@override
  Widget build(BuildContext context) {

    final AudioPlayerBloc audioPlayerBloc = BlocProvider.of<AudioPlayerBloc>(context);

    return MultiBlocProvider(
      providers: [
        BlocProvider<AudioPlayerBloc>(
          builder: (_) => AudioPlayerBloc(),
        )
      ],
      child: Scaffold(
          appBar: AppBar(
            title: Text('Global Audio Player'),
          ),
          body: Container(
            child: BlocBuilder<AudioPlayerBloc, MusicPlayerState>(
              builder: (context, state) {
                return Column(
                  children: <Widget>[
                    Flexible(
                        child: getListView(context)
                    ),
                    displayPlayer(state.player), // Here I'm trying to display the player when the AudioPlayerState is PLAYING
                  ],
                );
              },
            ),
          ),
      ),
    );

  }

全局功能

 Widget displayPlayer(AudioPlayer player){
    return MusicPlayer();
    if(player.state == AudioPlayerState.PLAYING) {
      return MusicPlayer();
    }
    return Container();
  }

EpisodesScreen.dart <-情节的ListView

class _EpisodesScreenState extends State<EpisodesScreen> {
  @override
  void initState() {
    super.initState();

    print(widget.series);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text(widget.series.name)),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Expanded(
              flex: 0,
              child: Image.network(widget.series.image.original),
            ),
            Expanded(
              child: getListView(context),
            ),
            Expanded(
              child: BlocBuilder<AudioPlayerBloc, MusicPlayerState>(
                builder: (context, state) {
                  return displayPlayer(state.player);
                },
              ),
            )
          ],
        ));
  }


  Widget getListView(BuildContext context) {
    List<Episode> episodesList = widget.series.episodes;

    final AudioPlayerBloc audioPlayerBloc =
        BlocProvider.of<AudioPlayerBloc>(context);

    var listView = ListView.separated(
      itemCount: episodesList.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text(episodesList[index].name),
          trailing: BlocBuilder<AudioPlayerBloc, MusicPlayerState>(
            builder: (context, state) {
              return FlatButton(
                onPressed: () {
                  audioPlayerBloc.dispatch(InitializePlayer(episodesList[index]));
                },
                child: Icon(
                  Icons.play_arrow,
                  color: Colors.black87,
                ),
              );
            },
          ),
        );
      },
      separatorBuilder: (BuildContext context, int index) {
        return Divider(
          height: 1.0,
          color: Colors.black12,
        );
      },
    );

    return listView;
  }
}

1 个答案:

答案 0 :(得分:0)

我错过了其中的yield *部分,现在可以使用了。

Stream<Duration> currentPosition() async* {
  yield* this.currentState.audioPlayer.onAudioPositionChanged;
}

Stream<Duration> fileDuration() async* {
  yield* this.currentState.audioPlayer.onDurationChanged;
}