-1

i'm making audio app with PageView and BottomNavigationBar, it should run the audio when isSelected is true and it's working but when I change pages it stop working and isSelected become false again, how to prevent that from happening? i'm also using AudioPlayers pagckage.

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int selectedIndex = 0;
  final PageController pageController = PageController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: PageView(
          controller: pageController,
          children: <Widget>[
            TimerPage(),
            TodoPage(),
            CalenderPage(),
            MusicPage(),
            SettingsPage(),
          ],
          onPageChanged: (pageIndex) {
            setState(() {
              selectedIndex = pageIndex;
            });
          },
        ),
      ),
      bottomNavigationBar: SizedBox(
        height: 70,
        child: ClipRRect(
          borderRadius: const BorderRadius.only(
            topRight: Radius.circular(25),
            topLeft: Radius.circular(25),
          ),
          child: BottomNavigationBar(
            onTap: (selectedIndex) {
              setState(() {
                pageController
                  ..animateToPage(selectedIndex,
                      duration: Duration(milliseconds: 500),
                      curve: Curves.ease);
              });
            },
            backgroundColor: MyColors.lightgray,
            selectedItemColor: MyColors.accentRed,
            unselectedItemColor: MyColors.disabledGrey,
            selectedFontSize: 15,
            unselectedFontSize: 15,
            type: BottomNavigationBarType.fixed,
            currentIndex: selectedIndex,
            showSelectedLabels: false,
            showUnselectedLabels: false,
            items: [
              BottomNavigationBarItem(
                icon: const Icon(FontAwesomeIcons.clock),
                label: "",
              ),
              BottomNavigationBarItem(
                icon: const FaIcon(FontAwesomeIcons.check),
                label: "",
              ),
              BottomNavigationBarItem(
                icon: const FaIcon(FontAwesomeIcons.calendarAlt),
                label: "",
              ),
              BottomNavigationBarItem(
                icon: const FaIcon(FontAwesomeIcons.music),
                label: "",
              ),
              BottomNavigationBarItem(
                icon: const FaIcon(FontAwesomeIcons.ellipsisH)
                label: "",
              ),
            ],
          ),
        ),
      ),
    );
  }
}

the play button:

class SoundChip extends StatefulWidget {
  final String title;
  final String image;
  final String audioName;
  final VoidCallback onPress;
  SoundChip({Key key, this.title, this.image, this.onPress, this.audioName})
      : super(key: key);

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

class _SoundChipState extends State<SoundChip> {
  bool isSelected = false;

  AudioPlayer audioPlayer = AudioPlayer();
  PlayerState audioPlayerState = PlayerState.PAUSED;
  AudioCache audioCache;

  play() async {
    await audioCache.loop(widget.audioName,
        stayAwake: true, mode: PlayerMode.LOW_LATENCY);
  }

  pause() async {
    await audioPlayer.pause();
  }

  @override
  void initState() {
    super.initState();
    audioCache = AudioCache(fixedPlayer: audioPlayer);
    audioPlayer.onPlayerStateChanged.listen((PlayerState state) {
      setState(() {
        audioPlayerState = state;
      });
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        if (audioPlayerState == PlayerState.PLAYING) {
          pause();
          isSelected = false;
        } else {
          play();
          isSelected = true;
        }
        widget.onPress();
      },
      child: AnimatedOpacity(
        opacity: isSelected ? 1 : 0.5,
        duration: Duration(milliseconds: 100),
        child: ClipRRect(
          borderRadius: BorderRadius.circular(20),
          child: AnimatedContainer(
            duration: Duration(seconds: 1),
            width: 160,
            height: 100,
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage(widget.image),
                fit: BoxFit.cover,
              ),
            ),
            child: Center(
                child: Text(
              widget.title,
              style: TextStyle(
                fontSize: 30,
                shadows: [
                  Shadow(
                    color: Colors.black,
                    blurRadius: 20,
                  ),
                ],
              ),
            )),
          ),
        ),
      ),
    );
  }
}
Ramez Sleem
  • 53
  • 1
  • 6

1 Answers1

12

Add AutomaticKeepAliveClientMixin to your page that you want to keep alive even if it is not in focus in the PageView.

How to add AutomaticKeepAliveClientMixin?

  1. Add with AutomaticKeepAliveClientMixin to your widget's state class.
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
...
}
  1. Add wantKeepAlive getter to your widget's state.
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
 bool get wantKeepAlive => true;
...
}
  1. Add super.build(context) to the build method of your widget's state.
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
 bool get wantKeepAlive => true;

@override
Widget build(BuildContext context) {
  super.build(context);
  return ...
 }
}
Andrej
  • 2,743
  • 2
  • 11
  • 28
  • I'm glad! If it helped you please consider clicking on the green checkmark to mark it as correct. Have a nice day :) – Andrej May 26 '21 at 05:40