每当ChangeNotifier触发事件时,是否存在一种优雅的方式来重置StatefulWidget的状态?

时间:2019-08-17 16:59:15

标签: flutter dart state

我正在尝试构建一个琐事应用,其中的挑战是通过听不同的吉他和弦来识别它们。

我有两个屏幕:一个用于主游戏,另一个用于设置,您可以在其中分别启用或禁用任何和弦。

所有和弦及其isEnabled状态的列表都存储在Flutter团队建议的通过package:provider实现的全局应用程序状态中。

import 'dart:math';

import 'package:flutter/material.dart';

class ChordCatalog extends ChangeNotifier {
  List<Chord> chords;

  ChordCatalog() {
    chords = List<Chord>();

    chords.add(Chord("D", List.generate(12, (i) => "d_${i + 1}.mp3")));
    // ...
    chords.add(Chord("Dmin", List.generate(9, (i) => "dmin_${i + 1}.mp3")));
  }

  List<Chord> get enabledChords => chords.where((chord) => chord.enabled).toList();

  void setEnabled(Chord chord, bool enabled) {
    chord.enabled = enabled;
    notifyListeners();
  }
}

class Chord {
  String name;
  bool enabled;

  List<String> _audioFiles;

  Chord(this.name, this._audioFiles) : enabled = true;

  String get audioFile => _audioFiles[Random().nextInt(_audioFiles.length)];
}

“设置”页面仅显示复选框列表并调用chordCatalog.setEnabled(...)

class Settings extends StalessWidget {
  @override
  Widget build(BuildContext context) {
    ChordCatalog catalog = Provider.of<ChordCatalog>(context);

    return Column(
      children: catalog.chords.map((chord) {
        return ListTile(
          title: Text("${chord.name}"),
          trailing: Checkbox(
            value: chord.enabled,
            onChanged: (val) {
              catalog.setEnabled(chord, val);
            },
          ),
        );
      }),
    ),
  }
}

主屏幕看起来像这样:

class Guesser extends StatefulWidget {
  @override
  State createState() {
    return GuesserState();
  }
}

class GuesserState extends State<Guesser> {
  Chord wantedChord;

  // Other fields hidden for simplicity

  void newGame() {
    List<Chord> chords = Provider.of<ChordCatalog>(context).enabledChords;
    setState(() {
      wantedChord = chords[Random().nextInt(chords.length)]
    });
  }

  @override
  Widget build(BuildContext context) {
    return Consumer<ChordCatalog>(
      builder: (context, catalog, _) {
        return Column(
          children: catalog.enabledChords.map((chord){
            return RaisedButton(
              child: Text("${chord.name}"),
              onPressed((){
                guess(chord);
              }),
            );
          }),
        ),
      },
    );
  }
}

我希望主页屏幕(Guesser)在状态更新时开始新游戏(这意味着用户进入设置并启用/禁用某些和弦),但是我不能在build内执行此操作,因为否则,我会通过调用setState来猜测或更新页面页面的UI元素时开始新游戏。

对于这种情况有什么好的解决方案?

0 个答案:

没有答案