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,
),
],
),
)),
),
),
),
);
}
}
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
?
with AutomaticKeepAliveClientMixin
to your widget's state class.class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
...
}
wantKeepAlive
getter to your widget's state.class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
...
}
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 ...
}
}