我有一个掷骰子MaterialApp
。当按下floatingButton
时,我想在 child 身上触发“骰子滚动”。我正在尝试使用InheritedWidget,但我看到的大多数示例似乎相反,会触发子级的父级更改。
无国籍 parent :
class DiceApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: Center(
child: Row(
children: <Widget>[
RollTrigger(
roller: Roller(),
child: Die(),
),
RollTrigger(
roller: Roller(),
child: Die(),
),
],
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.casino),
onPressed: () {
// Trigger the dice roll on each
},
),
),
);
}
}
}
InheritedWidget
:class RollTrigger extends InheritedWidget {
RollTrigger({this.roller, this.child});
final roller;
final Widget child;
static RollTrigger of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<RollTrigger>();
}
@override
bool updateShouldNotify(RollTrigger oldWidget) => true;
}
我正在尝试使用
Roller
类触发滚动操作:class Roller {
bool rolling = false;
void roll(_DieState die) {
die.roll();
}
}
最后是有状态的死亡:
class Die extends StatefulWidget {
@override
_DieState createState() => _DieState();
}
class _DieState extends State<Die> {
int value = 0;
final _random = new Random();
roll() {
this.value = 1 + _random.nextInt(6 - 1);
}
_DieState();
@override
Widget build(BuildContext context) {
var roller = RollTrigger.of(context).roller;
return Text(this.value.toString());
}
}
这似乎应该更简单一些,但我在这里将自己束缚在一起。
编辑:我通过将滚动条放在每个建议的最高级别进行更新。我仍然不确定如何触发底部小部件的重建:
final Roller roller = Roller();
...
RollTrigger(
roller: this.roller,
child: Die(),
)
然后将roll方法放入Roller中:
class Roller {
int value = 0;
final _random = new Random();
void roll() {
this.value = 1 + _random.nextInt(6 - 1);
print(this.value);
}
}
从
Roller
分配值:class _DieState extends State<Die> {
@override
Widget build(BuildContext context) {
final roller = RollTrigger.of(context).roller;
return Text(roller.value.toString());
}
}
最后,在顶层调用
roll
方法: floatingActionButton: FloatingActionButton(
child: Icon(Icons.casino),
onPressed: () {
this.roller.roll();
},
),
这将更新
Roller
的值,但绝不会更改_DieState的值...这是我要解决的问题。有很多有趣的模式,但我认为我正在努力的是基本实现。 最佳答案
是。它应该更简单!
您需要利用观察者设计模式。在Flutter中,可观察的是ChangeNotifier
。
包提供者将提供很大帮助。您创建的所有小部件类都可以是StatelessWidget
。
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Die with ChangeNotifier {
//
// _value can be one of null, 1, 2, 3, 4, 5, 6
// A value of null signifies the die is currently rolling.
//
int _value = 1;
final Random _random = Random();
int get value {
return this._value;
}
Future<void> roll() async {
if (this._value == null) {
// already rolling
return;
}
this._value = null;
this.notifyListeners();
await Future.delayed(Duration(seconds: 1));
this._value = 1 + this._random.nextInt(6);
this.notifyListeners();
}
}
// ---------------------------------------------------------
void main() {
return runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(final BuildContext context) {
return MaterialApp(
title: 'Die Rolling App',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(final BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<Die>(
create: (final BuildContext context) {
return Die();
},
),
],
child: Scaffold(
appBar: AppBar(title: const Text("Die Rolling Game")),
body: Center(child: DieDisplay()),
floatingActionButton: RollFAB(),
),
);
}
}
class DieDisplay extends StatelessWidget {
@override
Widget build(final BuildContext context) {
return Consumer<Die>(
builder: (final BuildContext context, final Die die, final Widget child) {
return Text((die.value == null) ? 'rolling' : die.value.toString());
},
);
}
}
class RollFAB extends StatelessWidget {
@override
Widget build(final BuildContext context) {
return FloatingActionButton(
onPressed: () {
final Die die = Provider.of<Die>(context, listen: false);
die.roll();
},
tooltip: 'Roll',
child: const Icon(Icons.casino),
);
}
}