Flutter - 如何在使用 PageView 或 BottomNavigationBar 更改页面时保持页面活动
Flutter - How to keep the page alive when changing it with PageView or BottomNavigationBar
我正在使用 PageView 和 BottomNavigationBar 制作音频应用程序,它应该 运行 isSelected
时的音频
是 true
并且它正在工作,但是当我更改页面时它停止工作并且 isSelected
再次变为 false
,如何防止这种情况发生?我也在使用 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: "",
),
],
),
),
),
);
}
}
播放按钮:
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,
),
],
),
)),
),
),
),
);
}
}
将 AutomaticKeepAliveClientMixin
添加到您想要保持活动状态的页面,即使它未在 PageView
中获得焦点。
如何添加AutomaticKeepAliveClientMixin
?
- 将
with AutomaticKeepAliveClientMixin
添加到您的小部件的状态 class。
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
...
}
- 将
wantKeepAlive
getter 添加到您的小部件的状态。
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true;
...
}
- 将
super.build(context)
添加到小部件状态的 build
方法。
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return ...
}
}
我正在使用 PageView 和 BottomNavigationBar 制作音频应用程序,它应该 运行 isSelected
时的音频
是 true
并且它正在工作,但是当我更改页面时它停止工作并且 isSelected
再次变为 false
,如何防止这种情况发生?我也在使用 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: "",
),
],
),
),
),
);
}
}
播放按钮:
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,
),
],
),
)),
),
),
),
);
}
}
将 AutomaticKeepAliveClientMixin
添加到您想要保持活动状态的页面,即使它未在 PageView
中获得焦点。
如何添加AutomaticKeepAliveClientMixin
?
- 将
with AutomaticKeepAliveClientMixin
添加到您的小部件的状态 class。
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
...
}
- 将
wantKeepAlive
getter 添加到您的小部件的状态。
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true;
...
}
- 将
super.build(context)
添加到小部件状态的build
方法。
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return ...
}
}