我正在尝试使用 flutter 创建一个收音机播放器应用程序。该应用程序只有 2 个屏幕,可通过 BottomNavigationBar(在本例中为 GNav)访问。
当我开始听广播时,播放按钮变成了暂停按钮。现在,当通过 BottomNavBar 切换屏幕然后再次返回播放器时,正在运行的广播播放器现在有一个播放按钮,而不是预期的暂停按钮,因为音频仍在播放。
当我开始听广播时,播放按钮变成了暂停按钮。现在,当通过 BottomNavBar 切换屏幕然后再次返回播放器时,正在运行的广播播放器现在有一个播放按钮,而不是预期的暂停按钮,因为音频仍在播放。
我很确定每次切换屏幕时都会调用
bool isPlaying = false;
。
我该怎么做才能使
bool isPlaying
每次回到播放器时都不会重置为“假”?
main.dart:
import 'package:flutter/material.dart';
import 'package:radio_orient/components/bottom_nav_bar.dart';
import 'package:radio_orient/pages/home.dart';
import 'package:radio_orient/pages/more_info.dart';
void main() {
runApp(RadioApp());
}
class RadioApp extends StatefulWidget {
@override
_RadioAppState createState() => _RadioAppState();
}
class _RadioAppState extends State<RadioApp> {
int _selectedIndex = 0;
void navigateBottomBar(int index) {
setState(() {
_selectedIndex = index;
});
}
final List<Widget> _pages = [Home(), const MoreInfo()];
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Radio Orient'),
backgroundColor: Color.fromARGB(255, 36, 120, 85),
),
body: _pages[_selectedIndex],
backgroundColor: const Color.fromRGBO(207, 185, 151, 1),
bottomNavigationBar: MyBottomNavBar(
onTabChange: (index) => navigateBottomBar(index),
),
),
);
}
}
home.dart:
import 'package:flutter/material.dart';
import 'package:radio_player/radio_player.dart';
class Home extends StatefulWidget {
Home({
super.key,
});
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
RadioPlayer _radioPlayer = RadioPlayer();
List<String>? metadata;
bool isPlaying = false;
void initRadioPlayer() {
_radioPlayer.setChannel(
title: 'My Radio',
url:
'https://myradio.url',
imagePath: 'assets/radio.jpg',
);
_radioPlayer.stateStream.listen((value) {
setState(() {
isPlaying = value;
});
});
_radioPlayer.metadataStream.listen((value) {
setState(() {
metadata = value;
});
});
}
@override
void initState() {
super.initState();
initRadioPlayer();
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FutureBuilder(
future: _radioPlayer.getArtworkImage(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
Image artwork;
if (snapshot.hasData) {
artwork = snapshot.data;
} else {
artwork = Image.asset(
'assets/radio.jpg',
fit: BoxFit.cover,
);
}
return SizedBox(
height: 180,
width: 180,
child: ClipRRect(
child: artwork,
borderRadius: BorderRadius.circular(15.0),
),
);
},
),
const SizedBox(height: 20),
const Text(
'Radio Orient Live',
softWrap: false,
overflow: TextOverflow.fade,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24),
),
Text(
metadata?[1] ?? '',
softWrap: false,
overflow: TextOverflow.fade,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
SizedBox(height: 20),
FloatingActionButton(
onPressed: () {
isPlaying ? _radioPlayer.pause() : _radioPlayer.play();
},
tooltip: 'Control button',
child: Icon(
isPlaying ? Icons.pause_rounded : Icons.play_arrow_rounded,
),
),
],
),
);
}
}
bottom_nav_bar.dart:
import "package:flutter/material.dart";
import "package:google_nav_bar/google_nav_bar.dart";
class MyBottomNavBar extends StatelessWidget {
void Function(int)? onTabChange;
MyBottomNavBar({super.key, required this.onTabChange});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 20),
child: GNav(
color: Colors.grey.shade400,
activeColor: Colors.grey.shade700,
tabActiveBorder: Border.all(color: Colors.white),
tabBackgroundColor: Colors.grey.shade100,
mainAxisAlignment: MainAxisAlignment.center,
tabBorderRadius: 16,
onTabChange: (value) => onTabChange!(value),
tabs: [
GButton(
icon: Icons.home,
text: 'Start',
),
GButton(
icon: Icons.info,
text: 'Info',
)
],
),
);
}
}
问题是,当您切换屏幕时,
state
会从树中删除。因此,要说 flutter 保持活动状态,您可以使用 mixin:AutomaticKeepAliveClientMixin
那么您的主屏幕将如下所示:
import 'package:flutter/material.dart';
import 'package:radio_player/radio_player.dart';
class Home extends StatefulWidget {
Home({
super.key,
});
@override
State<Home> createState() => _HomeState();
}
// add this mixin to your state definition
class _HomeState extends State<Home> with AutomaticKeepAliveClientMixin {
RadioPlayer _radioPlayer = RadioPlayer();
List<String>? metadata;
bool isPlaying = false;
// here you say that this state should be keept alive
@override
bool get wantKeepAlive => true;
void initRadioPlayer() {
_radioPlayer.setChannel(
title: 'My Radio',
url:
'https://myradio.url',
imagePath: 'assets/radio.jpg',
);
_radioPlayer.stateStream.listen((value) {
setState(() {
isPlaying = value;
});
});
_radioPlayer.metadataStream.listen((value) {
setState(() {
metadata = value;
});
});
}
@override
void initState() {
super.initState();
initRadioPlayer();
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FutureBuilder(
future: _radioPlayer.getArtworkImage(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
Image artwork;
if (snapshot.hasData) {
artwork = snapshot.data;
} else {
artwork = Image.asset(
'assets/radio.jpg',
fit: BoxFit.cover,
);
}
return SizedBox(
height: 180,
width: 180,
child: ClipRRect(
child: artwork,
borderRadius: BorderRadius.circular(15.0),
),
);
},
),
const SizedBox(height: 20),
const Text(
'Radio Orient Live',
softWrap: false,
overflow: TextOverflow.fade,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24),
),
Text(
metadata?[1] ?? '',
softWrap: false,
overflow: TextOverflow.fade,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
SizedBox(height: 20),
FloatingActionButton(
onPressed: () {
isPlaying ? _radioPlayer.pause() : _radioPlayer.play();
},
tooltip: 'Control button',
child: Icon(
isPlaying ? Icons.pause_rounded : Icons.play_arrow_rounded,
),
),
],
),
);
}
}
这里的文档:点击我