child 中的 Flutter 触发动作与 InheritedWidget
Flutter trigger action in child with InheritedWidget
我有一个dice-rollingMaterialApp
。当按下 floatingButton
时,我想在 children 上触发 "dice-roll"。我正在尝试使用 InheritedWidget,但我见过的大多数示例似乎都在做相反的事情,从 child.
触发 parent 更改
无国籍人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来触发滚动动作:
class Roller {
bool rolling = false;
void roll(_DieState die) {
die.roll();
}
}
最后是 Stateful Die:
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());
}
}
这似乎应该更简单,但我在这里陷入困境。
编辑:我根据建议将 Roller 置于顶层进行更新。我仍然不确定如何触发底部小部件的重建:
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 的值...这就是我要解决的问题。那里有很多有趣的模式,但我 认为 我正在努力解决的是基本实现。
This seems like it should be simpler, but I'm tying myself in knots here.
是的。应该会简单很多!
您需要利用观察者设计模式。在 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),
);
}
}
我有一个dice-rollingMaterialApp
。当按下 floatingButton
时,我想在 children 上触发 "dice-roll"。我正在尝试使用 InheritedWidget,但我见过的大多数示例似乎都在做相反的事情,从 child.
无国籍人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来触发滚动动作:
class Roller {
bool rolling = false;
void roll(_DieState die) {
die.roll();
}
}
最后是 Stateful Die:
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());
}
}
这似乎应该更简单,但我在这里陷入困境。
编辑:我根据建议将 Roller 置于顶层进行更新。我仍然不确定如何触发底部小部件的重建:
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 的值...这就是我要解决的问题。那里有很多有趣的模式,但我 认为 我正在努力解决的是基本实现。
This seems like it should be simpler, but I'm tying myself in knots here.
是的。应该会简单很多!
您需要利用观察者设计模式。在 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),
);
}
}