here is the widget I use it as the function to refresh my widgets (it is usually a floating button with onpressed capability), so I want to use key of my widget in here to refresh my widget
Widget floatingButton(int index){
if(index == 0){
return FloatingActionButton(
backgroundColor: Color.fromRGBO(29, 142, 41,1),
disabledElevation: 12,
child: Icon(Icons.refresh),
onPressed: () {
prefix0.Dashboard k = new prefix0.Dashboard();
k.createState().reassemble();
});
}
else return null;
}
and this is my widget which I want to refresh it, with its key "refresh" in the future builder
FutureBuilder(
key: refrKey,
future: model.tData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data == null) {
return Center(
child: Column(children: [
SizedBox(
height: MediaQuery.of(context).size.height / 6,),
Text('no data')
]));
} else { ...
I already got an answer ;
`
onPressed: () {
Navigator.push( context, new MaterialPageRoute(
builder: (context) => this.build(context)));
},
`
instead of using setState() which is not working as I want ,I rebuild the whole widget by call itself again and hance it get refreshed
The setState() method will initiate re-render the UI widget for whom the state actually belongs to. the setState() method does not initiate re-render whole UI as #Omi said. You can refer to the official article about Adding interactivity to your app. If you've managed the state correctly, it should reflect in UI automatically upon setState() call.
You don't refresh a widget. If, for instance, you want to change the text on the button, you use a string variable to hold the text and you change that variable in a setState. The system will do the rest.
Related
I'm having an issue trying to pop a dialog that contains a circle loader. I actually pop fine once my data is loaded, but in debug mode it's showing an exception that I can't figure out how to fix.
I have a stateful screen that on init I use the following code:
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
showLoading();
});
The method showLoading is as follows:
void showLoading() {
//let's show the loading bar
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
dialogContext = context;
return AppLoader();
},
);
}
Where AppLoader simply returns:
class AppLoader extends StatelessWidget {
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
backgroundColor: Colors.transparent,
body: Center(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
SizedBox(
child: new CircularProgressIndicator(),
height: 80.0,
width: 80.0,
),
],
),
),
);
}
}
dialogContent is defined in the initial of the class as:
late BuildContext dialogcontext;
The main bulk of my code looks like this:
#override
Widget build(BuildContext context) {
return Container(
color: ColorConstant.gray100,
child: Scaffold(
backgroundColor: ColorConstant.gray100,
body: Stack(
children: <Widget>[
getMainListViewUI(),
SizedBox(
height: MediaQuery.of(context).padding.bottom,
)
],
),
),
);
}
Widget getMainListViewUI() {
return FutureBuilder<bool>(
future: getData(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
return ListView.builder(
itemCount: listViews.length,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return listViews[index];
},
);
},
);
}
Basically, the issue that I have is that when I finish getting the data from (getData()), I use:
Navigator.pop(dialogContext);
This works great: it removes the circle loader and I can see the screen behind it, no issues, no errors. However, if I run in debug mode, when I do a hotsync, it always shows me the error:
Looking up a deactivated widget's ancestor on dialog pop
I understand that this is because of the Navigator.pop that I am doing, but I don't get it. I've defined the dialogContext, which is what I am passing to the showDialog, and that's what I am popping. I've also tried setting a scheduled navigator, but again, same issue.
Any advice please?
You can check if widget is mounted or not. This problem is likely to occur when you pass a context and have async function. Can you add this before navigation and see if problem is solved
if(!mounted) return;
Problem solved. The issue is the my getData method was being called multiple times, the first time it pops the loading widget fine, after that it would throw the error which is correct since the loading widget no longer exists.
titleColor: Colors.black,
resizeToAvoidBottomInset: false,
backgroundColor: Colors.white,
body: ProviderListener(
provider: addressNotifierProvider.state,
onChange: (context, state) {
if (state is AddressInitial) {
print("hello");
context
.read(addressNotifierProvider)
.fetchUserAddress(widget.addressIds);
}
},
child: Consumer(
builder: (context, watch, child) {
final state = watch(addressNotifierProvider.state);
print(state);
if(state is AddressInitial){
context
.read(addressNotifierProvider)
.fetchUserAddress(widget.addressIds);
}
if (state is AddressFetchedDetails) {
return SingleChildScrollView(
child: Container(
color: Colors.white,
padding: EdgeInsets.only(
This giving me error as soon as page opens Unhandled Exception: setState() or markNeedsBuild() called during build.
How to resolve this.
The fetchUserAddress operation changes the State of the widget (because of the watch I guess). A state change triggers a rebuild. But you are not allowed to trigger a rebuild during a build operation, as the error explains.
To resolve this you should rethink your state management architecture.
However, as a workaround you can wrap all state changing calls in a post render frame callback.
WidgetsBinding.instance
.addPostFrameCallback((_) => context
.read(addressNotifierProvider)
.fetchUserAddress(widget.addressIds) );
I'm trying to display a text based on the state of a bloc so I decided to use BlocListener as I think that's the main purpose of of the widget. I want to display a text when the state is AuthFailed.
BlocListener
BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
if (state is AuthFailed)
return Text(
'Oops, Invalid Credentials.',
style: TextStyle(color: Colors.red),
);
},
child: Container(),
),
The problem is, the text doesnt appear when the state is AuthFailed but If I use a BlocBuilder instead, it works.
BlocBuilder
BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is AuthFailed)
return Text(
'Oops, Invalid Credentials.',
style: TextStyle(color: Colors.red),
);
return Container(
width: 0,
height: 0,
);
},
),
You should use the BlocBuilder for that task. The purpose of the builder is to return a widget based on state.
The BlocListener is used for tasks such as routing or showing snackbar etc based on states. When you want to do something based on state.
The documentation is excellent, check it out:
https://pub.dev/packages/flutter_bloc
Furthermore, the listener function is a void function, so when you return the text widget, it is discarded. It you have linting on you would probably get a warning.
This is how we close a dialog from INSIDE
showSomeDialog() {
return showDialog(
context: context,
builder: (BuildContext contextPopup) {
return AlertDialog(
content: Center(
child: RaisedButton(
onPressed: () {
Navigator.of(contextPopup).pop();
},
child: Text('Close me inside'),
),
),);
}
);
}
How to close this dialog from OUTSIDE ? In other words, how does the stateful widget creating this dialog can access the variable contextPopup ? The problem with Navigator.of(context).pop() is that it will close the topmost widget on the Navigation stack, not this specific dialog.
In Android, to close a dialog programmatically from outside, you just do:
dialog.dismiss();
I have a statefull widget W1 which calls a stateless widget W2.
W2 has onTap functionality. I want to show an alert dialog in W2's onTap().
onTap:() {Alert(context: context, title:'Hi');},
I dont get any error, but no alert is shown on tap. I tried passing context as a parameter to W2 but I still dont see any dialog box.
What is the right way to show a dialog box from W2?
I am using rflutter_alert package Link
Thanks
You have to wrap your Alert(context: context, title:'Hi'); with showDialog(context: context, builder: (BuildContext context) => Alert(context: context, title:'Hi'));
Here is the cookbook sample:
Future<void> _neverSatisfied() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Rewind and remember'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('You will never be satisfied.'),
Text('You\’re like me. I’m never satisfied.'),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Regret'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Anyway, for your question about how to pass context, If you are creating a Stateless or Stateful widget you dont need to pass the context, you can get it from build(BuildContext context) {}.
Adding .show() in end solved it.
onTap:() {Alert(context: context, title:'Hi').show();}
Its clearly documented in rflutter_alert package, but I somehow missed it.
Pass the context in the function call in onTap:
onTap:(context) {Alert(context: context, title:'Hi');},