exception was thrown: setState() or markNeedsBuild() called during build - flutter

I'm little bit confusion about the this exception was thrown: setState() or markNeedsBuild() called during build. and I know it get resolved by this WidgetsBinding.instance.addPostFrameCallback((timeStamp) {}); code of line , but I want to understand why it happens, and why we use this addPostFrameCallback . I want to know deep concept about this exception with meaning , because this exception make me mad at sometimes , my code goes well suddenly it comes up. I don't know deeper but I think It is related to our state, I think our state is not build properly and the state got called again it makes a loop. that's why flutter throws this exception.
I have noticed, when I was newbie to the flutter , I put this setState() inside build method so this exception came up. where I got idea , This makes loops for states, all we know that setState() is use for rebuilding the states and call build method of widget tree , which rebuild our widgets with dynamic value.
If I have misconception about this exception , I would love to be clear by anyone.
I'm gonna attach the code below , where exception produced when goes to the screen for second time:
class UpcomingAppointmentsScreen extends StatelessWidget {
UpcomingAppointmentsScreen({Key? key}) : super(key: key);
AppointmentController controller = Get.find();
#override
Widget build(BuildContext context) {
controller.getupcomingAppointments(); //At this line exception comes up.
return Scaffold(
backgroundColor: MColors.colorBackgroundLight,
body: Stack(
children: [
Obx(() {
if (controller.upcomingAppointments.isEmpty &&
!(controller.upcomingAppoinmentLoadingState.value)) {
return Center(
child: Text(
'No upcoming appointments found',
style: TextStyle(
color: Colors.black,
fontSize: FontSize.largeTextSize,
fontWeight: FontWeight.bold),
),
);
} else {
return ListView.builder(
padding: const EdgeInsets.all(3),
itemCount: controller.upcomingAppointments.length,
itemBuilder: (context, index) {
var appointment = controller.upcomingAppointments[index];
return AppointmentCard(appointment);
});
}
}),
Obx(() {
return Visibility(
visible: controller.upcomingAppoinmentLoadingState.value,
child: Center(child: CircularProgressIndicator()));
})
],
),
);
}
}
Api call and set data to list of models :
getupcomingAppointments() {
upcomingAppoinmentLoadingState.value = true;
ApiCalls.appointmentsHistory().then((value) {
List list = value['Upcoming Appointments'];
upcomingAppointments.clear();
list.forEach((element) {
upcomingAppointments.add(AppointmentsData.fromJson(element));
});
upcomingAppoinmentLoadingState.value = false;
}).catchError((onError) {
upcomingAppoinmentLoadingState.value = false;
});
}

Related

Are states not passed to BlocBuilder widgets that are children of a BlocConsumer widget?

I am new to Flutter Bloc and must be missing how State changes are processed by the UI widgets. At the top level I have a BlocConsumer and under that I have nested BlocBuilder widgets with buildWhen methods to indicate when and how the Bloc widget should be rebuilt. Based on print statements,it looks like the Bloc state is consumed in the top level BlocConsumer widget and never makes it down to the lower level BlocBuilder widgets.
The code below should
Display circular progress bar on startup - this works ok
Call a bunch of APIs - This is happening
In the meantime display the initial screen with default text values in various widgets - this happens
As API returns and Bloc passes states on the stream, the appropriate UI widget should be rebuilt replacing default text with the data in the stream object. -- this doesn't happen.
Code snippets:
RaspDataStates issued by Bloc (Just showing for reference. Not showing all subclasses of RaspDataState):
#immutable
abstract class RaspDataState {}
class RaspInitialState extends RaspDataState {
#override
String toString() => "RaspInitialState";
}
class RaspForecastModels extends RaspDataState {
final List<String> modelNames;
final String selectedModelName;
RaspForecastModels(this.modelNames, this.selectedModelName);
}
...
Bloc just to show how initialized. Code all seems to work fine and isn't shown.
class RaspDataBloc extends Bloc<RaspDataEvent, RaspDataState> {
RaspDataBloc({required this.repository}) : super(RaspInitialState());
#override
RaspDataState get initialState => RaspInitialState();
...
Now to the UI widget.
class SoaringForecast extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocProvider<RaspDataBloc>(
create: (BuildContext context) =>
RaspDataBloc(repository: RepositoryProvider.of<Repository>(context)),
child: RaspScreen(repositoryContext: context),
);
}
}
class RaspScreen extends StatefulWidget {
final BuildContext repositoryContext;
RaspScreen({Key? key, required this.repositoryContext}) : super(key: key);
#override
_RaspScreenState createState() => _RaspScreenState();
}
class _RaspScreenState extends State<RaspScreen>
with SingleTickerProviderStateMixin, AfterLayoutMixin<RaspScreen> {
// Executed only when class created
#override
void initState() {
super.initState();
_firstLayoutComplete = false;
print('Calling series of APIs');
BlocProvider.of<RaspDataBloc>(context).add(GetInitialRaspSelections());
_mapController = MapController();
}
#override
void afterFirstLayout(BuildContext context) {
_firstLayoutComplete = true;
print(
"First layout complete. mapcontroller is set ${_mapController != null}");
_setMapLatLngBounds();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
drawer: AppDrawer.getDrawer(context),
appBar: AppBar(
title: Text('RASP'),
actions: <Widget>[
IconButton(icon: Icon(Icons.list), onPressed: null),
],
),
body: BlocConsumer<RaspDataBloc, RaspDataState>(
listener: (context, state) {
print('In forecastLayout State: $state'); << Can see all streamed states here
if (state is RaspDataLoadErrorState) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: Colors.green,
content: Text(state.error),
),
);
}
}, builder: (context, state) {
print('state is $state'); << Only see last streamed state here
if (state is RaspInitialState || state is RaspDataLoadErrorState) {
print('returning CircularProgressIndicator');
return Center(
child: CircularProgressIndicator(),
);
}
print('creating main screen'); << Only see this when all streams complete
return Padding(
padding: EdgeInsets.all(8.0),
child:
Column(mainAxisAlignment: MainAxisAlignment.start, children: [
getForecastModelsAndDates(),
getForecastTypes(),
displayForecastTimes(),
returnMap()
]));
}));
}
Widget getForecastModelsAndDates() {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
flex: 3,
child: forecastModelDropDownList(), // ForecastModelsWidget()
),
Expanded(
flex: 7,
child: Padding(
padding: EdgeInsets.only(left: 16.0),
child: forecastDatesDropDownList(),
)),
],
);
}
// Display GFS, NAM, ....
Widget forecastModelDropDownList() {
return BlocBuilder<RaspDataBloc, RaspDataState>(
buildWhen: (previous, current) {
return current is RaspInitialState || current is RaspForecastModels;
}, builder: (context, state) {
if (state is RaspInitialState || !(state is RaspForecastModels)) {
return Text("Getting Forecast Models");
}
var raspForecastModels = state;
print('Creating dropdown for models');
return DropdownButton<String>(
value: (raspForecastModels.selectedModelName),
isExpanded: true,
iconSize: 24,
elevation: 16,
onChanged: (String? newValue) {
BlocProvider.of<RaspDataBloc>(context)
.add(SelectedRaspModel(newValue!));
},
items: raspForecastModels.modelNames
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value.toUpperCase()),
);
}).toList(),
);
});
}
... more BlocBuilder child widgets similar to the one above
The print statements in the console are:
Calling series of APIs
state is RaspInitialState
returning CircularProgressIndicator
First layout complete. mapcontroller is set true
... (First of bunch of API output displays - all successful)
state is RaspInitialState << Not sure why this occurs again
returning CircularProgressIndicator
... (More API output displays - all successful)
streamed RaspForecastModels
In forecastLayout State: Instance of 'RaspForecastModels' << Doesn't cause widget to be rebuild
streamed RaspForecastDates << Other states being produced by Bloc
In forecastLayout State: Instance of 'RaspForecastDates'
streamed RaspForecasts
In forecastLayout State: Instance of 'RaspForecasts'
In forecastLayout State: Instance of 'RaspForecastTime'
streamed RaspMapLatLngBounds
In forecastLayout State: Instance of 'RaspMapLatLngBounds'
state is Instance of 'RaspMapLatLngBounds'
creating main screen
Any words of wisdom on the errors of my way would be appreciated.
I added this earlier as a comment but then found Stackoverflow didn't initially show my comment (I needed to click on show more). So here it is in better readable form.
Problem solved. I needed to move the line:
BlocProvider.of<RaspDataBloc>(context).add(GetInitialRaspSelections());
from the initState() method to afterFirstLayout().
All blocbuilders then executed and the UI was built appropriately . And to answer my title question, the bloc states are broadcast and can be picked up by different BlocBuilders.

Flutter, ListView.builder onTap strange behavior

On press key 1, ListView adds 1 tile, on press key 2 ListView removes one tile, though after clicking with mouse outside of ListView or Text() widget, keyboard keys stop responding without any error being shown in terminal.
I thought, that maybe FocusNode was disposed after clicking outside of ListView, though, after testing, this seems not to be the case
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class OnTapWidgetIssue extends StatefulWidget {
OnTapWidgetIssue({Key? key}) : super(key: key);
String testOnTap = '';
int nOfList = 1;
#override
_OnTapWidgetIssueState createState() => _OnTapWidgetIssueState();
}
class _OnTapWidgetIssueState extends State<OnTapWidgetIssue> {
final FocusNode _focusNode = FocusNode();
#override
void dispose() {
_focusNode.dispose();
print('_focusNode.dispose()');
super.dispose();
}
void _handleKeyEvent(RawKeyEvent event) {
if (event is RawKeyDownEvent &&
event.data.logicalKey == LogicalKeyboardKey.digit1) {
widget.nOfList += 1;
setState(() {});
}
if (event is RawKeyDownEvent &&
event.data.logicalKey == LogicalKeyboardKey.digit2) {
if (widget.nOfList > 1) {
widget.nOfList--;
setState(() {});
} else {}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: MenuDrawer(),
appBar: AppBar(title: Text('OnTap-widget.Issue')),
body: RawKeyboardListener(
autofocus: true,
focusNode: _focusNode, // <-- more magic
onKey: _handleKeyEvent,
child: Column(children: [
Text(widget.testOnTap, style: TextStyle(fontSize: 52.0)),
Text('''
press 1 to add ListTile
press 2 to remove ListTile
'''),
Expanded(
child: Row(
children: [
Expanded(
flex: 2,
child: SizedBox(),
),
Expanded(
flex: 1,
// child: SizedBox(),
// // ),
child: ListView.builder(
itemCount: widget.nOfList,
// itemCount: widget.testOnTap.length,
itemBuilder: (_, i) {
return ListTile(
title: Text('$i'),
onTap: () {
widget.testOnTap = widget.testOnTap + i.toString();
setState(() {});
},
// Handle your onTap here.
);
},
),
),
Expanded(
flex: 2,
child: SizedBox(),
),
],
),
),
]),
),
);
}
}
Also Im getting error when clicking to go to new page in the app
Error: A FocusNode was used after being disposed.
Once you have called dispose() on a FocusNode, it can no longer be used.
at Object.throw_ [as throw] (http://localhost:49535/dart_sdk.js:5061:11)
at http://localhost:49535/packages/flutter/src/foundation/change_notifier.dart.lib.js:66:21
at focus_manager.FocusNode.new.[_debugAssertNotDisposed] (http://localhost:49535/packages/flutter/src/foundation/change_notifier.dart.lib.js:69:25)
at focus_manager.FocusNode.new.notifyListeners (http://localhost:49535/packages/flutter/src/foundation/change_notifier.dart.lib.js:131:41)
at focus_manager.FocusNode.new.[_notify] (http://localhost:49535/packages/flutter/src/widgets/widget_inspector.dart.lib.js:42893:12)
at focus_manager.FocusManager.new.[_applyFocusChange] (http://localhost:49535/packages/flutter/src/widgets/widget_inspector.dart.lib.js:43665:26)
at Object._microtaskLoop (http://localhost:49535/dart_sdk.js:38778:13)
at _startMicrotaskLoop (http://localhost:49535/dart_sdk.js:38784:13)
at http://localhost:49535/dart_sdk.js:34519:9
How ever, I don't get this error when selecting exercise page in drawer menu, only when going to this new page from home page. Exercise and Home pages are kinda similar, but still different in some aspects.
Thank
Technically, you are not adding the onTap to the ListView.builder, you're adding it to every single ListTile added by the builder. :)
Declare your two state variables:
String testOnTap = '';
int nOfList = 1;
inside the _OnTapWidgetIssueState class, not the OnTapWidgetIssue class. The convention is to name them _testOnTap and _nOfList respectively since they are private to the class.
And update the two variables INSIDE the setState call, not outside it.

Update List Item After Delete Action in Flutter

Hello I am new to flutter and I have a problem to update the list after executing a deleting an item from the database. Some said to use setState, but I still don't know how to implement it in my code. Tried to call seState right after the delete action, but still nothing happened. Still have some trouble to understand which component to update in Flutter. Thank you.
class ProfileView extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _ProfileViewState();
}
}
class _ProfileViewState extends State<ProfileView> {
late Future<List<Patient>> _patients;
late PatientService patientService;
#override
void initState() {
super.initState();
patientService = PatientService();
_patients = patientService.getPatient();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Profile')),
body: Column(
children: <Widget>[
Flexible(
child: SizedBox(
child: FutureBuilder<List<Patient>>(
future: _patients,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasError) {
print(snapshot);
return Center(
child: Text("Error"),
);
} else if (snapshot.hasData){
List<Patient> patients = snapshot.data;
return _buildListView(patients);
} else {
return Center(
child: Container(),
);
}
},
),
),
)
],
),
);
}
Widget _buildListView(List<Patient> patients) {
return ListView.separated(
separatorBuilder: (BuildContext context, int i) => Divider(color: Colors.grey[400]),
itemCount: patients.length,
itemBuilder: (context, index) {
Patient patient = patients[index];
return Row(
children: <Widget>[
Flexible(
child: SizedBox(
child: ListTile(
title: Text(patient.firstName),
subtitle: Text(patient.phone),
trailing: IconButton(
icon: new Icon(const IconData(0xf4c4, fontFamily: 'Roboto'), size: 48.0, color: Colors.red),
onPressed: () {
patientService.deletePatient(patient.id.toString());
}),
),
)
)
],
);
}
);
}
}
You can achieve that by removing the initialization of the future from the initState and simply give the future of patientService.getPatient() to the FutureBuilder, like this:
future: patientService.getPatient()
And call setState after making sure the patient have been successfully deleted.
The explanation behind doing that is when you delete your patient from the DB, yes it is removed from there, but the UI didn't get an update about the list of patients after the delete. And the reason why calling setState in your case doesn't make a change is because you are assigning the future in initState which is called once and only once when the widget is initialized. So when you call setState the future won't be called again hence no new data is fetched.
So what I did is just remove the initialization of the future from initState and give it to the FutureBuilder, which will be rebuild whenever you call setState.
Even though this works, it isn't the ideal solution. Because you are rebuilding your whole widget every time a delete is made which is kinda of heavy considering the FutureBuilder, so what I suggest is checking out some state mangement solutions like Bloc or Mobx or even the Provider package (which isn't a state mangement according to its creator).
Hope that makes clear !
Happy coding !
call setState() inside the onPressed method.
onPressed: () {
patientService.deletePatient(patient.id.toString());
setState((){});
}),
If you are not saving a local copy of the list from which you are deleting an item then this works
Although if the delete method deletes on from wherever you are fetching the items then you will need to call
_patients = patientService.getPatient();
before calling setState()
I think your deletePatient is asynchronous method. And you are calling this method without await and after this function setState is called thus widget is getting updated before delete is completed.
If deletePatient is asynchronous then add await before calling it and add setState after it.
onPressed: () async {
await patientService.deletePatient(patient.id.toString());
setState((){});
})

Flutter when ListView.builder is refreshed it goes back from the beggining and not from the maxScrollExtent point

I am new in Flutter and I am facing a problem.
What I have so far is that I am getting the data from a web service asynchronously (Json). So in the build method I use a FutureBuilder widget for Scaffold's body argument. And its 'builder' argument (of FutureBuilder widget) returns a ListView.builder to show the data.
Also I use ScrollController for scrolling.
Its time I reach the maximum scroll point I call once again the service to get the next page of data and so on...
The problem is that when I "change page" by scrolling it brings the data correctly, but it starts from the very first line of data and not from the point where i ve reached the maxScrollExtent point.
So if the first 'snapshot' has 25 rows and the second has 15, when I go to the second it starts from row 1 and not from row 26 although the total amount of data row is 40 correctly .
As a result i don't have a smooth scrolling. I have been stuck for enough time to this point and i do not know what I am missing. Do I have to use Page Storage keys (i saw video from flutter team but i haven't found an edge to my problem). Any hints? A sample of code follows.
class _MyAppState extends State<MyApp> {
final ScrollController _controller = ScrollController();
#override
void initState() {
super.initState();
_controller.addListener(_scrollListener);
}
void _scrollListener() {
if (_controller.offset >= _controller.position.maxScrollExtent &&
!_controller.position.outOfRange) {
if (nextDataSet != null) {
print('nextDataSet = ' + nextDataSet);
setState(() {
inDataSet = nextDataSet;
});
} else {
print('nextDataSet = NULL');
}
}
Future<Post> fetchPost([String dataSet]) async {
...
return Post.fromJson(json.decode(utf8.decode(response.bodyBytes)));
}
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Scaffold(
...
body: FutureBuilder<Post>(
future: fetchPost(inDataSet),
builder: _buildList,
),
),
),
);
}
Widget _buildList(BuildContext context, AsyncSnapshot snapshot) {
... /*code that eventually fills the lists of strings
progressivePartyListSec, progressivePartyListThird*/
...
return ListData(controller: _controller, listEidosPerigr:
progressivePartyListSec, listPerigr: progressivePartyListThird );
}
}
class ListData extends StatelessWidget {
final ScrollController controller;
final List<String> listEidosPerigr;
final List<String> listPerigr;
ListData({this.controller,
this.listEidosPerigr,
this.listPerigr});
#override
Widget build(BuildContext context) {
return ListView.builder(
controller: controller,
itemCount: rowsSelected,
itemBuilder: (context, i) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
removeAllHtmlTags(listEidosPerigr[i]),
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.blue),
),
new RichText(
text: new TextSpan(
text: listPerigr[i].replaceAllMapped('<BR>', (Match m) => '').replaceAllMapped('<b>', (Match m) => '').replaceAllMapped('</b>', (Match m) => ''),
style: DefaultTextStyle.of(context).style,
),
),
]);
});
}
}
after some research i found a solution in the following link: Flutter: Creating a ListView that loads one page at a time
Thanks a lot AbdulRahman AlHamali.
Basically, on the above code that i have posted, i used another argument for the ListView.builder and it is the following key: PageStorageKey('offset'),
Finally as AbdulRahman writes on his article i used the KeepAliveFutureBuilder as a wrapper of FutureBuilder in other worlds in my build method i did...
body: KeepAliveFutureBuilder(
//child: FutureBuilder<Post>(
future: fetchPost(inDataSet),
builder: _buildList,
//),
),

flutter_gauge widget won't update index value on setState

The problem I'm having is that although I'm successfully updating a value of my meter (FlutterGauge) widget via setState, the widget itself does not reflect that change. I know that the rebuild is happening, and that the value on the meter widget is indeed being updated.
void updateScore(bool isOnTopic) {
//for the purposes of testing we won't use isOnTopic (its a hardcoded true anyway)
setState(() {
meterScore += 15;
});
print("Score Updated:");
print("--------" + meterScore.toString() + "--------");
}
#override
Widget build(BuildContext context) {
print('+++++++We\'re building! Using this.meterScore value: ' +
meterScore.toString() +
'+++++++');
//Replacing my FlutterGauge and return with the line below as a way to isolate the FlutterGauge widget as the problem
//return Center(child: Text(this.meterScore.toString()));
FlutterGauge meter = new FlutterGauge(
circleColor: meterColor,
secondsMarker: SecondsMarker.none,
hand: Hand.short,
number: Number.none,
width: 200,
index: meterScore,
fontFamily: "Iran",
counterStyle: TextStyle(color: Colors.black, fontSize: 35),
counterAlign: CounterAlign.center,
isDecimal: false);
print("------------Accessing meter.index: " +
meter.index.toString() +
"----------------");
return meter;
}
I'm fairly certain that the issue is how I'm using the FlutterGauge widget from the flutter_gauge package because when I replace it with a simple Text widget, and feed my value to it, it will update and reflect the update as expected.
That being the case, here is a link to flutter_gauge for reference:
https://pub.dev/packages/flutter_gauge#-readme-tab-
I'm pretty new to flutter and this is my first stackoverflow question, so apologies if I'm making any obvious mistakes. Thanks in advance!
Just in case there's important code I'm leaving out that you may need to see, here is the entire file:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_gauge/flutter_gauge.dart';
class Meter extends StatefulWidget {
Meter({Key key}) : super(key: key);
MeterState createState() => MeterState();
}
class MeterState extends State<Meter> {
#override
initState() {
super.initState();
}
double meterScore = 75;
Color meterColor = Colors.green;
void updateMeterColor() {
setState(() {
meterColor = Colors.green;
});
}
void updateScore(bool isOnTopic) {
//for the purposes of testing we won't use isOnTopic (its a hardcoded true anyway)
setState(() {
meterScore += 15;
});
print("Score Updated:");
print("--------" + meterScore.toString() + "--------");
}
#override
Widget build(BuildContext context) {
print('+++++++We\'re building! Using this.meterScore value: ' +
meterScore.toString() +
'+++++++');
//Replacing my FlutterGauge and return with the line below as a way to isolate the FlutterGauge widget as the problem
//return Center(child: Text(this.meterScore.toString()));
FlutterGauge meter = new FlutterGauge(
circleColor: meterColor,
secondsMarker: SecondsMarker.none,
hand: Hand.short,
number: Number.none,
width: 200,
index: meterScore,
fontFamily: "Iran",
counterStyle: TextStyle(color: Colors.black, fontSize: 35),
counterAlign: CounterAlign.center,
isDecimal: false);
print("------------Accessing meter.index: " +
meter.index.toString() +
"----------------");
return meter;
}
#override
void dispose() {
print("---------We are disposing (as intended)------------");
super.dispose();
}
}
EDITS:
here is my terminal after a hot restart and initial visit:
I/flutter (11573): +++++++We're building! Using this.meterScore value: 75.0+++++++
I/flutter (11573): ------------Accessing meter.index: 75.0----------------
I/flutter (11573): 75.0
invoking the function once:
I/flutter (11573): Score Updated:
I/flutter (11573): --------90.0--------
I/flutter (11573): +++++++We're building! Using this.meterScore value: 90.0+++++++
I/flutter (11573): ------------Accessing meter.index: 90.0----------------
I updated the code snippets (removed the this. from all meterScore, added a comment addressing the function's unused argument)
I should probably mention that the updateScore function is being called outside the file. As I said, the function itself seems to work fine as the print statements indicate.
here is where i'm using the widget (this is the entire file):
class RecordingPage extends StatefulWidget {
RecordingPage({Key key}) : super(key: key);
_RecordingPageState createState() => _RecordingPageState();
}
class _RecordingPageState extends State<RecordingPage> {
final GlobalKey<MeterState> meterState = GlobalKey<MeterState>();
int yes = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Container(
width: this.yes * 10.0,
child: FittedBox(
child: FloatingActionButton(
onPressed: null,
backgroundColor: Colors.white,
))),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
backgroundColor: Colors.white,
appBar: offTopTitle,
body: Column(
children: <Widget>[
Row(children: [
Expanded(
child: FlatButton(
child: Text("Go To Websocket"),
color: Colors.blue,
onPressed: () {
Navigator.pushNamed(context, WebsocketRoute);
},
),
),
]),
Container(
height: MediaQuery.of(context).size.height / 4,
child: Image.asset('assets/placeholderWave.gif'),
),
Container(
margin: EdgeInsets.only(top: 5),
height: MediaQuery.of(context).size.height / 4,
child: Meter(key: meterState),
),
Recorder((isOnTopic) {
meterState.currentState.updateScore(isOnTopic);
}),
],
),
bottomNavigationBar: AppBarBuilder());
}
}
After toying around with the package in a new flutter project I have been unable to get it to update after creation using many different ways and after looking at all available documentation for the package at this time, I am not sure it is meant to be used in this way. There are no examples of changing the gauge after it is built so it appears to be an immutable widget.
I did some digging and the syncfusion_flutter_gauges looks like a promising alternative and this article goes over how to do what I think you are attempting in your project. Hope it helps
I think I found the solution. This worked for me. Open flutter_gauge.dart and remove all the commented section. Reinstall back your app and refresh your data. This steps works for me.