skip to Main Content

I have a main screen named "ItemsScreen". inside of this has a listview.builder. I have a widget named "ItemCard" for creating listview items.

Problem – I want to stop audio when a user navigates between different screens in my flutter app.

  • One navigation has inside of ItemCard
  • Other navigation has main screen.

If any time, User navigate to any screen, I want to stop audio If it is playing.

I’m using audioplayers: ^5.1.0 package. – link

ItemsScreen like this:

class _YourWidgetState extends State<YourWidget> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        itemCount: 3,
        itemBuilder: (context, index) {
          return ItemCard(
            audioUrl: 'audio_url_for_YourWidget');
        },
      ),
      //navigate to setting screen
      floatingActionButton: FloatingActionButton(
        onPressed: () {
           // ------------------------------------------------ navigation
          Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => SettingScreen(),
                ),
              );
        },
        child: Icon(Icons.settings),
      ),
    );
  }
}

ItemCard like this:

    class ItemCard extends StatefulWidget {
  final String audioUrl;

  ItemCard({
    required this.audioUrl,
  });

  @override
  _ItemCardState createState() => _ItemCardState();
}

class _ItemCardState extends State<ItemCard> {
  bool isPlaying = false;

  
  void _loadAudio() async {
    if (!isPlaying) {
      setState(() {
        loading = true;
        isStarted = true;
      });
      await audioPlayer.play(
        UrlSource(
            'https://firebasestorage.googleapis.com/v0/b/voice-feed.appspot.com/o/audio%2F1694248558321?alt=media&token=20194024-0060-43e5-b66c-dd10ec4537a0'),
      );

      setState(() {
        loading = false;
      });
    } else {
      await audioPlayer.pause();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: [
          ElevatedButton(
            onPressed:  _loadAudio,
            child: Text(isPlaying ? 'Pause' : 'Play'),
          ),
          // ------------------------------------------------ navigation
          ElevatedButton(
            onPressed:  (){
               Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (_) => ItemViewScreen(),
                    ),
                  );
            }
            child: Text('View the item'),
          ),
        ],
      ),
    );
  }
}

2

Answers


  1. Chosen as BEST ANSWER

    Finally, find a way to do this task.

    import 'package:flutter/material.dart';
    import 'package:audioplayers/audioplayers.dart';
    import 'package:provider/provider.dart';
    
    class AudioPlayerManager with ChangeNotifier {
      AudioPlayer audioPlayer = AudioPlayer();
      int currentlyPlayingIndex = -1;
      bool isPaused = false;
    
      Future<void> playAudio(String audioUrl, int index) async {
        if (currentlyPlayingIndex != -1) {
          if (isPaused) {
            await audioPlayer.resume();
            isPaused = false;
          } else {
            await audioPlayer.stop();
          }
        }
    
        await audioPlayer.play(UrlSource(audioUrl));
        currentlyPlayingIndex = index;
    
        notifyListeners();
      }
    
      void pauseAudio() async {
        if (currentlyPlayingIndex != -1) {
          await audioPlayer.pause();
          isPaused = true;
          notifyListeners();
        }
      }
    
      void stopAudio() async {
        if (currentlyPlayingIndex != -1) {
          await audioPlayer.stop();
          currentlyPlayingIndex = -1;
          isPaused = false;
          notifyListeners();
        }
      }
    }
    
    void main() {
      runApp(
        ChangeNotifierProvider(
          create: (_) => AudioPlayerManager(),
          child: MyApp(),
        ),
      );
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: YourWidget(),
        );
      }
    }
    
    class YourWidget extends StatefulWidget {
      @override
      State<YourWidget> createState() => _YourWidgetState();
    }
    
    class _YourWidgetState extends State<YourWidget> {
      final List<String> audioUrls = [
        
      ];
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: ListView.builder(
            itemCount: 3,
            itemBuilder: (context, index) {
              return ItemCard(
                audioUrl: audioUrls[index],
                index: index,
              );
            },
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              // Pause audio when navigating to the SettingScreen.
              Provider.of<AudioPlayerManager>(context, listen: false).pauseAudio();
    
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (_) => SettingScreen(),
                ),
              ).then((_) {
                // Resume audio when returning from the SettingScreen.
                Provider.of<AudioPlayerManager>(context, listen: false).playAudio(
                  audioUrls[Provider.of<AudioPlayerManager>(context, listen: false)
                      .currentlyPlayingIndex],
                  Provider.of<AudioPlayerManager>(context, listen: false)
                      .currentlyPlayingIndex,
                );
              });
            },
            child: Icon(Icons.settings),
          ),
        );
      }
    }
    
    class ItemCard extends StatefulWidget {
      final String audioUrl;
      final int index;
    
      ItemCard({
        required this.audioUrl,
        required this.index,
      });
    
      @override
      _ItemCardState createState() => _ItemCardState();
    }
    
    class _ItemCardState extends State<ItemCard> {
      bool isPlaying = false;
    
      @override
      void dispose() {
        // Stop audio when the ItemCard is disposed (navigated away).
        Provider.of<AudioPlayerManager>(context, listen: false).stopAudio();
        super.dispose();
      }
    
      void _loadAudio() async {
        final audioPlayerManager =
            Provider.of<AudioPlayerManager>(context, listen: false);
    
        if (isPlaying) {
          // Toggle pause/play for the currently playing audio.
          audioPlayerManager.pauseAudio();
        } else {
          audioPlayerManager.playAudio(widget.audioUrl, widget.index);
        }
    
        setState(() {
          isPlaying = !isPlaying;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        final audioManager = Provider.of<AudioPlayerManager>(context);
    
        return Container(
          child: Column(
            children: [
              ElevatedButton(
                onPressed: _loadAudio,
                child: Text(isPlaying ? 'Pause' : 'Play'),
              ),
              ElevatedButton(
                onPressed: () {
                  Provider.of<AudioPlayerManager>(context, listen: false)
                      .stopAudio();
    
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (_) => ItemViewScreen(),
                    ),
                  );
    
                  
                },
                child: Text('View the item'),
              ),
            ],
          ),
        );
      }
    }
    
    class SettingScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Setting Screen'),
          ),
          body: Center(
            child: Text('Setting Screen Content'),
          ),
        );
      }
    }
    
    class ItemViewScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Item View Screen'),
          ),
          body: Center(
            child: Text('Item View Screen Content'),
          ),
        );
      }
    }
    

  2. For this you have to define a audio player outside of any class or function like thisenter image description here

    Then whenever you navigate to screen you can have a init method, that will be called as soon as screen is called and then you can play, pause or stop the audio

    @override
      void initState() {
      super.initState();
      player.stop();
    }
    

    So on your main screen that is item screen you can have it like this

    class _YourWidgetState extends State<YourWidget> {
       @override
         void initState() {
         super.initState();
         player.stop();
       }
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: ListView.builder(
            itemCount: 3,
            itemBuilder: (context, index) {
              return ItemCard(
                audioUrl: 'audio_url_for_YourWidget');
            },
          ),
          //navigate to setting screen
          floatingActionButton: FloatingActionButton(
            onPressed: () {
               // ------------------------------------------------ navigation
              Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (_) => SettingScreen(),
                    ),
                  );
            },
            child: Icon(Icons.settings),
          ),
        );
      }
    }
    

    You can apply it in same way in another screen.
    And don’t forget to import the player from where you have defined it. Also don’t dispose the player, after disposing it you will not be able to play any thing on it

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search