Solved the issue, though there is still one bug, please check the edit section for more info on the bug!
I have issue with setState in my app, basically I have Number input and Multiplier input TextField, and every time I input any of those, I would like app to show/update result/results in text widget/widgets.
When value is provided in number TextField, only text widget behind it in the same row should update, and this works as expected.
When value is provided/updated in Multiplier TextField all text widgets on the screen should be updated and this is not happening
In both Multiplier and number TextField I'm using setState for purpose of updating Text widgets, which I would like to have updated every time I enter/update value in either Multiplier or number field, when value is provided in Multiplier field, all Text widgets that are behind non empty number field should update(not working). While when value is provided in number field, only text widget behind it should update (this is working as expected).
Thank for your time
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: new LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Scaffold(
body: new Column(
children: <Widget>[
HeaderRow(),
InputRow(inputRowID: 0),
InputRow(inputRowID: 1),
InputRow(inputRowID: 2),
InputRow(inputRowID: 3),
InputRow(inputRowID: 4),
InputRow(inputRowID: 5),
],
),
);
}), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class HeaderRow extends StatefulWidget {
static var multiplier;
@override
_HeaderRowState createState() => _HeaderRowState();
}
class _HeaderRowState extends State<HeaderRow> {
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Row(
children: [
Expanded(
flex: 1,
child: Container(
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Multiplier',
),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
], // Only numbers can be entered
onChanged: (String str) {
setState(() {
HeaderRow.multiplier = str;
calculate();
});
},
),
),
),
],
),
],
);
}
}
class InputRow extends StatefulWidget {
final int inputRowID;
InputRow({@required this.inputRowID});
static List<String> number = ['0', '0', '0', '0', '0', '0'];
static List<double> result = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
static var resultToString = [
'awaiting input...',
'awaiting input...',
'awaiting input...',
'awaiting input...',
'awaiting input...',
'awaiting input...',
'awaiting input...',
];
@override
_InputRowState createState() => _InputRowState();
}
class _InputRowState extends State<InputRow> {
@override
Widget build(BuildContext contex) {
return Column(
children: <Widget>[
Row(
children: [
Expanded(
flex: 1,
child: Container(
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'number',
),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
], // Only numbers can be entered
onChanged: (String str) {
setState(() {
InputRow.number[widget.inputRowID] = str;
calculate();
print(InputRow.resultToString[widget.inputRowID]);
});
},
),
),
),
Expanded(
flex: 1,
child: Container(
child: Text(
InputRow.resultToString[widget.inputRowID],
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
],
);
}
}
void calculate() {
for (int ctr = 0; ctr < InputRow.result.length; ctr++) {
InputRow.result[ctr] =
double.parse(InputRow.number[ctr]) * double.parse(HeaderRow.multiplier);
InputRow.resultToString[ctr] = InputRow.result[ctr].toStringAsFixed(2);
}
}
EDIT
Was able to solve the issue by removing InputRow()'s widgets from MyHomePage class and adding them to the end of HeaderRow() class instead and now it works almost perfectly.
However there is still one bug, whenever I delete all input in any of the number input fields, app will stop update results for all of the Text widgets, even though in other number fields and multiplier field there is input. Though if I enter numbers in all of the number fields, app works again as expected.
If anyone has idea how to solve this issue, thank you for the help.
Updated code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: new LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Scaffold(
body: new Column(
children: <Widget>[
HeaderRow(),
],
),
);
}), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class HeaderRow extends StatefulWidget {
static var multiplier;
@override
_HeaderRowState createState() => _HeaderRowState();
}
class _HeaderRowState extends State<HeaderRow> {
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Row(
children: [
Expanded(
flex: 1,
child: Container(
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Multiplier',
),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
], // Only numbers can be entered
onChanged: (String str) {
setState(() {
HeaderRow.multiplier = str;
calculate();
});
},
),
),
),
],
),
InputRow(inputRowID: 0),
InputRow(inputRowID: 1),
InputRow(inputRowID: 2),
InputRow(inputRowID: 3),
InputRow(inputRowID: 4),
InputRow(inputRowID: 5),
],
);
}
}
class InputRow extends StatefulWidget {
final int inputRowID;
InputRow({@required this.inputRowID});
static List<String> number = ['0', '0', '0', '0', '0', '0'];
static List<double> result = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
static var resultToString = [
'awaiting input...',
'awaiting input...',
'awaiting input...',
'awaiting input...',
'awaiting input...',
'awaiting input...',
'awaiting input...',
];
@override
_InputRowState createState() => _InputRowState();
}
class _InputRowState extends State<InputRow> {
@override
Widget build(BuildContext contex) {
return Column(
children: <Widget>[
Row(
children: [
Expanded(
flex: 1,
child: Container(
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'number',
),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
], // Only numbers can be entered
onChanged: (String str) {
setState(() {
InputRow.number[widget.inputRowID] = str;
calculate();
print(InputRow.resultToString[widget.inputRowID]);
});
},
),
),
),
Expanded(
flex: 1,
child: Container(
child: Text(
InputRow.resultToString[widget.inputRowID],
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
],
);
}
}
void calculate() {
for (int ctr = 0; ctr < InputRow.result.length; ctr++) {
InputRow.result[ctr] =
double.parse(InputRow.number[ctr]) * double.parse(HeaderRow.multiplier);
InputRow.resultToString[ctr] = InputRow.result[ctr].toStringAsFixed(2);
}
}
Your setState((){})
only rebuilds the build method of InputRow
class. You need to rebuild the build method of MyHomePage
to update all those fields. User Provider . Create a separate class to contains the value of those fields and notifyListeners()
to update UI.
class Results extends ChangeNotifier{
//your logics
void calculate() {
//your calculations
notifyListeners();
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.