从 flutter 的子事件中调用 setState?
Calling setState from a child event in flutter?
每当应用程序从串行设备(使用 usb_serial 包)接收数据时,我需要重新绘制 UI。
TextEditingController cntrl = TextEditingController();
...
ListView(
children:[
TextButton(
onPressed: () async {
port = await _deviceList[0].create();
bool? openResult = await port?.open();
if (!openResult!) {
SmartDialog.showToast("Failed to connect!");
return;
}
port?.setPortParameters(
globals.baudRate,
globals.dataBits,
globals.stopBits,
globals.parity,
);
SmartDialog.showToast("Connected!");
port?.inputStream?.listen((Uint8List event) {
setState(() {
_cntrl.text=utf8.decode(event);
});
});
},
child: const Text("Start"),
style: startButtonStyle,
),
TextField(
controller: _cntrl,
),
],
)
但是 UI 永远不会重绘。如果我必须从子事件调用 setState() 但找不到任何答案,我在网上搜索了很多关于应该做什么的信息。可能的解决方案是什么?
编辑:
显然这只是一些奇怪的错误,我将相同的代码复制到一个新项目中,它开始运行得很好。
一个简单的方法是传递一个函数给child,例如:
class MyChildWidget extends StatelessWidget {
final VoidCallback onRefresh; // The callback that will be called to refresh parent state
const MyChildWidget({Key? key, required this.onRefresh}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => onRefresh(), // Call the callback when button is tapped
child: Text('Refresh Parent'),
);
}
}
现在使用MyChildWidget
时,可以传入onRefresh
参数,让它在parent中执行setState
,例如:
MyChildWidget(
onRefresh: () => setState(() {}),
);
这将是进行一些简单状态管理的简单方法。当事情变得太复杂时,您可以研究一些更高级的状态管理解决方案,例如 StreamBuilder
或 provider
包。
更新:
根据你更新的问题,问题不在 set state
。也许您的 input stream
没有发出事件。您可以尝试添加 print
语句来检查流是否正常工作。
试试这个更短的代码来测试“将状态设置为 TextField”的概念,您应该会看到它按预期工作:
final _controller = TextEditingController();
// ...
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () => setState(() {
_controller.text = 'Hello World';
}),
child: const Text('Set text'),
),
TextField(
controller: _controller,
),
],
)
每当应用程序从串行设备(使用 usb_serial 包)接收数据时,我需要重新绘制 UI。
TextEditingController cntrl = TextEditingController();
...
ListView(
children:[
TextButton(
onPressed: () async {
port = await _deviceList[0].create();
bool? openResult = await port?.open();
if (!openResult!) {
SmartDialog.showToast("Failed to connect!");
return;
}
port?.setPortParameters(
globals.baudRate,
globals.dataBits,
globals.stopBits,
globals.parity,
);
SmartDialog.showToast("Connected!");
port?.inputStream?.listen((Uint8List event) {
setState(() {
_cntrl.text=utf8.decode(event);
});
});
},
child: const Text("Start"),
style: startButtonStyle,
),
TextField(
controller: _cntrl,
),
],
)
但是 UI 永远不会重绘。如果我必须从子事件调用 setState() 但找不到任何答案,我在网上搜索了很多关于应该做什么的信息。可能的解决方案是什么?
编辑: 显然这只是一些奇怪的错误,我将相同的代码复制到一个新项目中,它开始运行得很好。
一个简单的方法是传递一个函数给child,例如:
class MyChildWidget extends StatelessWidget {
final VoidCallback onRefresh; // The callback that will be called to refresh parent state
const MyChildWidget({Key? key, required this.onRefresh}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => onRefresh(), // Call the callback when button is tapped
child: Text('Refresh Parent'),
);
}
}
现在使用MyChildWidget
时,可以传入onRefresh
参数,让它在parent中执行setState
,例如:
MyChildWidget(
onRefresh: () => setState(() {}),
);
这将是进行一些简单状态管理的简单方法。当事情变得太复杂时,您可以研究一些更高级的状态管理解决方案,例如 StreamBuilder
或 provider
包。
更新:
根据你更新的问题,问题不在 set state
。也许您的 input stream
没有发出事件。您可以尝试添加 print
语句来检查流是否正常工作。
试试这个更短的代码来测试“将状态设置为 TextField”的概念,您应该会看到它按预期工作:
final _controller = TextEditingController();
// ...
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () => setState(() {
_controller.text = 'Hello World';
}),
child: const Text('Set text'),
),
TextField(
controller: _controller,
),
],
)