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?

  1. with AutomaticKeepAliveClientMixin 添加到您的小部件的状态 class。
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
...
}
  1. wantKeepAlive getter 添加到您的小部件的状态。
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
 bool get wantKeepAlive => true;
...
}
  1. super.build(context) 添加到小部件状态的 build 方法。
class _MyWidgetState extends State<MyWidget> with AutomaticKeepAliveClientMixin {
 bool get wantKeepAlive => true;

@override
Widget build(BuildContext context) {
  super.build(context);
  return ...
 }
}