我正在尝试构建一个琐事应用,其中的挑战是通过听不同的吉他和弦来识别它们。
我有两个屏幕:一个用于主游戏,另一个用于设置,您可以在其中分别启用或禁用任何和弦。
所有和弦及其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元素时开始新游戏。
对于这种情况有什么好的解决方案?