如何更改有状态小部件中的布尔值?
How do i change a boolean in a StatefullWidget from another one?
我是 Flutter 的新手。
我正在尝试按一个按钮打开一个面板,而不是按该面板上的一个按钮将其关闭。
我已经通过在同一页面中编写代码来做到这一点。
我不能做的是拆分代码并保持一切正常。
我实际上在做的是在初始化为 False 的小部件的状态中调用一个变量,然后使用我正在调用的 if 语句:或我想要的空容器或面板。
当我按下我调用 SetState(){} 的按钮时,变量变为 true 让面板出现,然后在面板中有一个按钮做相反的事情。
假设我所做的是正确的。如何在新页面中重构面板时继续执行此操作?
我对流和继承的小部件有些了解,但我还没有完全理解
如果您想打开一个对话框(而不是您所说的 "panel"),您可以在再次关闭对话框时简单地返回所选数据。
你可以在这里找到一个很好的教程:https://medium.com/@nils.backe/flutter-alert-dialogs-9b0bb9b01d28
如果我没理解错的话,你想从另一个StatefullWidget
通知一个StatefullWidget
。关于这个有几种方法,但既然你提到了 Streams
,我将尝试 post 举个例子来解释一下这种情况。
所以基本上,您可以将流视为一端连接到水龙头的管道,另一端添加到一个杯子中(末端可以分成多个末端并放入多个杯子,"broadcast streams").
现在,杯子是听众(订阅者)并等待水从管道中落下。
水龙头是发射器,打开水龙头就会喷出水滴。
将水龙头的另一端放入杯子中即可打开,这是一个带有一些很酷的传感器的智能水龙头,(当“检测到”订阅者时,发射器将开始发射事件)。
水滴是应用程序中发生的实际事件。
此外,您必须记得关闭水龙头,以免杯子大量泄漏到厨房地板上。 (您必须在处理完事件后取消订阅者以避免泄漏)。
现在,对于您的特定情况,这里的代码片段可以说明上述隐喻:
class ThePannel extends StatefulWidget { // this is the cup
final Stream<bool> closeMeStream; // this is the pipe
const ThePannel({Key key, this.closeMeStream}) : super(key: key);
@override
_ThePannelState createState() => _ThePannelState(closeMeStream);
}
class _ThePannelState extends State<ThePannel> {
bool _closeMe = false;
final Stream<bool> closeMeStream;
StreamSubscription _streamSubscription;
_ThePannelState(this.closeMeStream);
@override
void initState() {
super.initState();
_streamSubscription = closeMeStream.listen((shouldClose) { // here we listen for new events coming down the pipe
setState(() {
_closeMe = shouldClose; // we got a new "droplet"
});
});
}
@override
void dispose() {
_streamSubscription.cancel(); // THIS IS QUITE IMPORTANT, we have to close the faucet
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
SomeWidgetHere(shouldClose: _closeMe),
RaisedButton(
onPressed: () {
setState(() {
_closeMe = true;
});
},
)
],
);
}
}
class SomeWidgetThatUseThePreviousOne extends StatefulWidget { // this one is the faucet, it will emit droplets
@override
_SomeWidgetThatUseThePreviousOneState createState() =>
_SomeWidgetThatUseThePreviousOneState();
}
class _SomeWidgetThatUseThePreviousOneState
extends State<SomeWidgetThatUseThePreviousOne> {
final StreamController<bool> thisStreamWillEmitEvents = StreamController(); // this is the end of the pipe linked to the faucet
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
ThePannel(closeMeStream: thisStreamWillEmitEvents.stream), // we send the other end of the pipe to the cup
RaisedButton(
child: Text("THIS SHOULD CLOSE THE PANNEL"),
onPressed: () {
thisStreamWillEmitEvents.add(true); // we will emit one droplet here
},
),
RaisedButton(
child: Text("THIS SHOULD OPEN THE PANNEL"),
onPressed: () {
thisStreamWillEmitEvents.add(false); // we will emit another droplet here
},
)
],
);
}
@override
void dispose() {
thisStreamWillEmitEvents.close(); // close the faucet from this end.
super.dispose();
}
}
我希望我的类比能帮助您稍微理解流的概念。
您可以像这样从另一个屏幕导航和 return 数据:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Returning Data',
home: HomeScreen(),
));
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Returning Data Demo'),
),
body: Center(child: SelectionButton()),
);
}
}
class SelectionButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: Text('Pick an option, any option!'),
);
}
// A method that launches the SelectionScreen and awaits the result from
// Navigator.pop!
_navigateAndDisplaySelection(BuildContext context) async {
// Navigator.push returns a Future that will complete after we call
// Navigator.pop on the Selection Screen!
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result!
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("$result")));
}
}
class SelectionScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pick an option'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Yep!" as the result
Navigator.pop(context, 'Yep!');
},
child: Text('Yep!'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Nope!" as the result
Navigator.pop(context, 'Nope.');
},
child: Text('Nope.'),
),
)
],
),
),
);
}
}
有关导航的更多详细信息:
https://flutter.dev/docs/cookbook/navigation/returning-data
我是 Flutter 的新手。
我正在尝试按一个按钮打开一个面板,而不是按该面板上的一个按钮将其关闭。
我已经通过在同一页面中编写代码来做到这一点。
我不能做的是拆分代码并保持一切正常。
我实际上在做的是在初始化为 False 的小部件的状态中调用一个变量,然后使用我正在调用的 if 语句:或我想要的空容器或面板。
当我按下我调用 SetState(){} 的按钮时,变量变为 true 让面板出现,然后在面板中有一个按钮做相反的事情。
假设我所做的是正确的。如何在新页面中重构面板时继续执行此操作?
我对流和继承的小部件有些了解,但我还没有完全理解
如果您想打开一个对话框(而不是您所说的 "panel"),您可以在再次关闭对话框时简单地返回所选数据。 你可以在这里找到一个很好的教程:https://medium.com/@nils.backe/flutter-alert-dialogs-9b0bb9b01d28
如果我没理解错的话,你想从另一个StatefullWidget
通知一个StatefullWidget
。关于这个有几种方法,但既然你提到了 Streams
,我将尝试 post 举个例子来解释一下这种情况。
所以基本上,您可以将流视为一端连接到水龙头的管道,另一端添加到一个杯子中(末端可以分成多个末端并放入多个杯子,"broadcast streams").
现在,杯子是听众(订阅者)并等待水从管道中落下。
水龙头是发射器,打开水龙头就会喷出水滴。
将水龙头的另一端放入杯子中即可打开,这是一个带有一些很酷的传感器的智能水龙头,(当“检测到”订阅者时,发射器将开始发射事件)。
水滴是应用程序中发生的实际事件。
此外,您必须记得关闭水龙头,以免杯子大量泄漏到厨房地板上。 (您必须在处理完事件后取消订阅者以避免泄漏)。
现在,对于您的特定情况,这里的代码片段可以说明上述隐喻:
class ThePannel extends StatefulWidget { // this is the cup
final Stream<bool> closeMeStream; // this is the pipe
const ThePannel({Key key, this.closeMeStream}) : super(key: key);
@override
_ThePannelState createState() => _ThePannelState(closeMeStream);
}
class _ThePannelState extends State<ThePannel> {
bool _closeMe = false;
final Stream<bool> closeMeStream;
StreamSubscription _streamSubscription;
_ThePannelState(this.closeMeStream);
@override
void initState() {
super.initState();
_streamSubscription = closeMeStream.listen((shouldClose) { // here we listen for new events coming down the pipe
setState(() {
_closeMe = shouldClose; // we got a new "droplet"
});
});
}
@override
void dispose() {
_streamSubscription.cancel(); // THIS IS QUITE IMPORTANT, we have to close the faucet
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
SomeWidgetHere(shouldClose: _closeMe),
RaisedButton(
onPressed: () {
setState(() {
_closeMe = true;
});
},
)
],
);
}
}
class SomeWidgetThatUseThePreviousOne extends StatefulWidget { // this one is the faucet, it will emit droplets
@override
_SomeWidgetThatUseThePreviousOneState createState() =>
_SomeWidgetThatUseThePreviousOneState();
}
class _SomeWidgetThatUseThePreviousOneState
extends State<SomeWidgetThatUseThePreviousOne> {
final StreamController<bool> thisStreamWillEmitEvents = StreamController(); // this is the end of the pipe linked to the faucet
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
ThePannel(closeMeStream: thisStreamWillEmitEvents.stream), // we send the other end of the pipe to the cup
RaisedButton(
child: Text("THIS SHOULD CLOSE THE PANNEL"),
onPressed: () {
thisStreamWillEmitEvents.add(true); // we will emit one droplet here
},
),
RaisedButton(
child: Text("THIS SHOULD OPEN THE PANNEL"),
onPressed: () {
thisStreamWillEmitEvents.add(false); // we will emit another droplet here
},
)
],
);
}
@override
void dispose() {
thisStreamWillEmitEvents.close(); // close the faucet from this end.
super.dispose();
}
}
我希望我的类比能帮助您稍微理解流的概念。
您可以像这样从另一个屏幕导航和 return 数据:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Returning Data',
home: HomeScreen(),
));
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Returning Data Demo'),
),
body: Center(child: SelectionButton()),
);
}
}
class SelectionButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: Text('Pick an option, any option!'),
);
}
// A method that launches the SelectionScreen and awaits the result from
// Navigator.pop!
_navigateAndDisplaySelection(BuildContext context) async {
// Navigator.push returns a Future that will complete after we call
// Navigator.pop on the Selection Screen!
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result!
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("$result")));
}
}
class SelectionScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pick an option'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Yep!" as the result
Navigator.pop(context, 'Yep!');
},
child: Text('Yep!'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: () {
// Close the screen and return "Nope!" as the result
Navigator.pop(context, 'Nope.');
},
child: Text('Nope.'),
),
)
],
),
),
);
}
}
有关导航的更多详细信息: https://flutter.dev/docs/cookbook/navigation/returning-data