Reputation: 5905
I have a Future Builder that builds a ListView.builder, The builder ListTiles are build by another widget that have an ontap function. I have figured out how to get something to run on the final widget by using the back button, but have not been able to figure out how to call something on the original widget on back button. For instance, I need to refresh the top level data when the user clicks back button and not just the data in the secondary widget which is already working.
I hope this makes sense, any help would be great.
UPDATE Here is the code. I am simplifying what I am showing because making a simple example will lose the context. Below you see that I have a FutureBuilder that returns a ListBuilder that returns a new ChatWidget. This is the top level, this Future needs to be refreshed when I click on the back button. However the onTap to trap the callback is in the ChatWidget.
new Expanded(
child: new RefreshIndicator(
child: new FutureBuilder<List<Map>>(
future: chatlist,
builder: (BuildContext context, AsyncSnapshot<List<Map>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none: return new Text('Waiting to start');
case ConnectionState.waiting: return new Text('Loading...');
default:
if (snapshot.hasError) {
return new Text('Error: ${snapshot.error}');
} else {
return new ListView.builder(
itemBuilder: (context, index) {
ChatServerList mychat = new ChatServerList(snapshot.data[index]['msgkey'],snapshot.data[index]['refid'],snapshot.data[index]['referralname'], snapshot.data[index]['oid'],snapshot.data[index]['sendname'],snapshot.data[index]['pid'],snapshot.data[index]['receivename'],snapshot.data[index]['pgrpid'],snapshot.data[index]['prid'],snapshot.data[index]['message'],);
bool isgroup = true;
if (mychat.grpid == 0) {
isgroup = false;
}
return new ChatWidget(mychat: mychat,threaded: threaded, isgroup: isgroup);
},
itemCount: snapshot.data.length,
);
}
}
},
),
onRefresh: _onRefresh
),
)
This is built in the ChatWidget, you notice the _onTap:
new MyListTile(
leading: new CircleAvatar(
child: _chatAvatar(),
//child: !isgroup ? _indMsg() : _grpMsg(), radius: 18.0,
),
//subtitle: new Text(widget.mychat.oname),
title: new Text(widget.mychat.referralname),
trailing: new Text(widget.mychat.oname, textAlign: TextAlign.right,),
//isThreeLine: true,
//onTap: doTap(threaded),
onTap: _onTap,
onLongPress: _doArchive,
),
new MyListTile(
leading: new Text(' '),
title: new Text(submymessage, textAlign: TextAlign.left,
style: new TextStyle(fontSize: 15.0,
color: Colors.grey, fontStyle: FontStyle.italic),),
trailing: _unreadBabdge(),
onTap: _onTap,
onLongPress: _doArchive,
),
That _onTap is below and has the code to handle the back button.
_onTap() async {
ChatDB.instance.updateRead(widget.mychat.msgkey);
if (threaded) {
//TODO
} else {
Route route = new MaterialPageRoute(
settings: new RouteSettings(name: "/ChatServerDivided"),
builder: (BuildContext context) => new ChatServerDivided(mychat: widget.mychat, title: "Chat Messages",),
);
//Navigator.of(context).push(route);
var nav = await Navigator.of(context).push(route);
if(nav==true||nav==null){
unread = ChatDB.instance.getUnread(widget.mychat.msgkey);
}
}
}
So what I am trying to find is if this code can somehow commmunicate up to the originating widget so that I can run the original Future again. I hope this makes more sense and is easier to understand.
Upvotes: 0
Views: 2451
Reputation: 4356
Yes you can do that. Couldn't see exactly where to fit it into your code but I'll give you the way to handle this. The navigator calls are all Futures which means you can await them on the calling side. It seems like you're just missing passing a value to the .pop call. Below is an example.
Where you navigate you can await for your result
var navigationResult = await Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => Page2()));
Then you can check the navigationResult with a simple if.
if(navigationResult == 'rerun_future') {
uploadFiles(); // Perform your custom functionality here.
}
The way you pass that information back is that when you do a pop call (to navigate back) you'll pass the value 'rerun_future' in there.
Navigator.of(context).pop('rerun_future')
Additionally if you also want to add this functionality to the back button you should surround your Scaffold with WillPopScope, return false to onWillPop and supply a leading item to the appBar where you perform your custom pop call. Example below from this post
@override
Widget build(BuildContext context) {
return new WillPopScope(
onWillPop: () async => false,
child: new Scaffold(
appBar: new AppBar(
title: new Text("data"),
leading: new IconButton(
icon: new Icon(Icons.ac_unit),
onPressed: () => Navigator.of(context).pop('rerun_future'), //<----- pass value here too
),
),
),
);
}
Upvotes: 4