flutter - Flutter Callback with return error setState() or markNeedsBuild called during build
问题描述
I use PopupMenuButton to edit the listView. For every action PopupMenuButton (remove item, add item, edit item in listView) trying to do Callback. For example, the simplest case is to delete
//_editorChannels - data with which I fill in the list
delete(dynamic val) {
setState(() => _editorChannels.removeWhere((data) => data == val));
}
But since I pass the callback function delete
to the widget, when I create it I get error setState() or markNeedsBuild called during build. If change and remove the setState()
, then no error occurs, but of course the list will not be updated when the item is deleted via callback.
delete(dynamic val) {
_editorChannels.removeWhere((data) => data == val);
}
My PopupMenuButton Widget
class PopMenuWidget2 extends StatelessWidget {
final VoidCallback onDelete;
const PopMenuWidget2({Key key, this.onDelete}) : super(key: key);
@override
Widget build(BuildContext context) => PopupMenuButton<int>(
onSelected: (result) {
//On View
if (result == 0) {}
//On Edit
if (result == 1) { }
//OnDelete Callback run
if (result == 2) {
onDelete();
}
},
itemBuilder: (context) => [
PopupMenuItem(
value: 0,
child: Row(
children: <Widget>[
Icon(
Icons.remove_red_eye_rounded,
color: Colors.black38,
),
Text(' View Option', style: TextStyle(color: Colors.black38)),
],
),
),
PopupMenuItem(
value: 1,
child: Row(
children: <Widget>[
Icon(
Icons.create,
color: Colors.black38,
),
Text(' Edit Option', style: TextStyle(color: Colors.black38)),
],
),
),
PopupMenuItem(
value: 2,
child: Row(
children: <Widget>[
Icon(
Icons.delete,
color: Colors.black38,
),
Text(' Delete Option',
style: TextStyle(color: Colors.black38)),
],
),
),
],
);
}
Main Widget
class EditorPage extends StatefulWidget {
EditorPage({Key key, this.Channels}) : super(key: key);
final List<Channel> Channels;
static const String routeName = "/EditorPage";
@override
_EditorPageState createState() => new _EditorPageState();
}
class _EditorPageState extends State<EditorPage> {
Stream<Mock> _result;
final _coreObj = new Core();
List<Channel> _editorChannels;
//callback onDelete
delete(dynamic val) {
setState(() => _editorChannels.removeWhere((data) => data == val));
}
@override
void initState() {
_editorChannels = widget.Channels;
super.initState();
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: new Scaffold(
appBar: AppBar(
title: Text(''),
bottom: TabBar(tabs: [
Tab(icon: FaIcon(FontAwesomeIcons.calendarCheck), text: "One"),
Tab(icon: FaIcon(FontAwesomeIcons.tasks), text: "Two"),
]),
),
body: SafeArea(
child: TabBarView(children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Scaffold(
body: ListView.builder(
itemCount: _editorChannels == null
? 0
: _editorChannels.length,
itemBuilder: (context, index) {
final item = _editorChannels[index];
return Card(
shadowColor: Colors.black26,
margin: EdgeInsets.all(3.0),
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(2),
),
child: ListTile(
title: Container(
child: Text(
item.Name != null ? item.Name : '',
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0),
)),
subtitle: Text(item.Url),
onTap: () => {},
isThreeLine: false,
leading: getIconbyId(item.Status),
//Pass callback
trailing: PopMenuWidget2(
onDelete: delete(item),
)),
);
}),
),
)
],
),
]))));
}
}
解决方案
为了setState()
工作,您需要拥有PopMenuWidget2
as StatefulWidget
。改变
class PopMenuWidget2 extends StatelessWidget {
至
class PopMenuWidget2 extends StatefulWidget {
还传递你的回调函数,比如它上面的链接,而不是函数执行的结果
onDelete: () => onDelete(item)
trailing: PopMenuWidget(
onDelete: () => onDelete(item),
)),
完整代码:
class PopMenuWidget2 extends StatefulWidget {
final VoidCallback onDelete;
const PopMenuWidget2({Key key, this.onDelete}) : super(key: key);
@override
_PopMenuWidget2State createState() => _PopMenuWidget2State();
}
class _PopMenuWidget2State extends State<PopMenuWidget2> {
@override
Widget build(BuildContext context) => PopupMenuButton<int>(
onSelected: (result) {
//On View
if (result == 0) {}
//On Edit
if (result == 1) { }
//OnDelete Callback run
if (result == 2) {
onDelete();
}
},
itemBuilder: (context) => [
PopupMenuItem(
value: 0,
child: Row(
children: <Widget>[
Icon(
Icons.remove_red_eye_rounded,
color: Colors.black38,
),
Text(' View Option', style: TextStyle(color: Colors.black38)),
],
),
),
PopupMenuItem(
value: 1,
child: Row(
children: <Widget>[
Icon(
Icons.create,
color: Colors.black38,
),
Text(' Edit Option', style: TextStyle(color: Colors.black38)),
],
),
),
PopupMenuItem(
value: 2,
child: Row(
children: <Widget>[
Icon(
Icons.delete,
color: Colors.black38,
),
Text(' Delete Option',
style: TextStyle(color: Colors.black38)),
],
),
),
],
);
}
推荐阅读
- bash - Bash 脚本以 sudo 密码作为变量打开新的 gnome 终端
- android - 如何预填充 Android Room 数据库?
- c++ - 将指针类分配给新类,C++
- javascript - 如何创建从 Google App 脚本到 Web App 的消息框
- docker - Nginx + 多个 docker 容器在同一 IP 但使用 SSL 的不同端口
- php - Magento2,如何在rest API订单详细信息中显示和获取sales_order表的自定义表列?
- angular - Heroku github 部署失败的角度应用程序
- reactjs - 组件在 React.js 中重定向到其组件本身
- python - 如何删除所有以某个值开头的值?
- android - Inno Setup SignTool Error 2 系统找不到指定的文件