Flutter回调,返回在生成过程中调用的错误setState()或markNeedsBuild



我使用PopupMenuButton来编辑listView。对于PopupMenuButton(在listView中删除项、添加项、编辑项(尝试进行回调的每个操作。例如,最简单的情况是删除

//_editorChannels - data with which I fill in the list
delete(dynamic val) {
setState(() => _editorChannels.removeWhere((data) => data == val));
}

但是,由于我将回调函数delete传递给小部件,所以当我创建它时,会在构建过程中调用错误setState((或markNeedsBuild。如果更改并删除setState(),则不会发生错误,但当通过回调删除项目时,列表当然不会更新。

delete(dynamic val) {
_editorChannels.removeWhere((data) => data == val);
}

我的弹出菜单按钮小部件

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)),
],
),
),
],
);
}

主要小工具

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作为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)),
],
),
),
],
);
}

您必须定义自定义类型:,而不是使用VoidCallback

typedef MyCustomCallback<T> = void Function(T value);

并将onDelete定义更改为:

final MyCustomCallback onDelete;

最后将回调调用修复为:

if (result == 2) {
onDelete(value);
}

// ...
trailing: PopMenuWidget2(
onDelete: (item) => delete(item),
)),

最新更新