我希望能够编辑TextField,并在填充完所有文本后,计算一个值。每次用户更改值时,都必须重新计算该值。
我试过Streams和Controller。流正在做得很好,即使价值的更新是用1个变化的数据完成的。即height
,weight
和age
都必须是!= null
,当我们在第一个{height: 2, weight:3, age:2}
时,它没有计算,在其中一个被更改之后,结果计算但是使用上述数据。相反,控制器似乎根本不听变量变化。
在这里,我在另一个类中初始化控制器
class Bsmi extends StatelessWidget {
StreamController<void> valueBoxStream = StreamController<void>.broadcast();
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new DefaultAppBar(context: context, title: Text(" ")),
body: new ListView(
children: <Widget>[
BsmiResult(valueBoxStream, {}),
new Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
),
child: ListView(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
padding: EdgeInsets.all(20.0),
itemExtent: 80.0,
children: <Widget>[
_BsmiResultState().indices("height", valueBoxStream),
_BsmiResultState().indices("weight", valueBoxStream),
_BsmiResultState().indices("age", valueBoxStream),
],
),
),
],
),
);
}
}
这是重要的代码
class BsmiResult extends StatefulWidget {
final StreamController<void> valueBoxStream;
const BsmiResult(this.valueBoxStream, this.data);
final Map data;
@override
_BsmiResultState createState() =>
_BsmiResultState(valueBoxStream: this.valueBoxStream, data: this.data);
}
class _BsmiResultState extends State<BsmiResult> {
_BsmiResultState({this.valueBoxStream, this.data});
StreamController<void> valueBoxStream;
final Map data;
final textFieldController = new TextEditingController();
int weight;
int age;
int height;
String _result = "0.0";
_printLatestValue() {
print("Second text field: ${textFieldController.text}");
}
void setData(data) {
if (data['type'] == 'height') {
print("I'm inside height\n");
height = int.parse(data['value']);
} else if (data['type'] == 'weight') {
print("I'm inside weight\n");
weight = int.parse(data['value']);
} else {
print("I'm inside age\n");
age = int.parse(data['value']);
}
}
@override
void initState() {
super.initState();
textFieldController.addListener(_printLatestValue);
valueBoxStream.stream.listen((_){
_calculateResult();
});
}
@override
void dispose() {
// Clean up the controller when the Widget is removed from the Widget tree
textFieldController.dispose();
super.dispose();
}
void _calculateResult() {
if ((height != null) && (height != 0) && (weight != null) && (weight != 0) && (age != null) && (age != 0)) {
print("height: " +
height.toString() +
"" +
" weight: " +
weight.toString() +
" age: " +
age.toString());
_result = ((height + weight) / age).toString();
print(_result + "\n");
} else {
_result = "0.0";
}
}
@override
Widget build(BuildContext context) {
return new Column(
children: <Widget>[
new Text("Risultato"),
new Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
), //For the controller i don't use the StreamBuilder but a normal Text("$_result"),
child: StreamBuilder(
stream: valueBoxStream.stream,
builder: (context, snapshot) {
if (snapshot.hasData || _result != "0.0") {
print(snapshot.data);
setData(snapshot.data);
return new Text(
"$_result",
textAlign: TextAlign.end,
);
} else {
return new Text(
"0.0",
textAlign: TextAlign.end,
);
}
},
),
),
],
);
}
Row indices(String text, StreamController<void> valueBoxStream) {
return new Row(
children: <Widget>[
leftSection(text),
rightSection(text, valueBoxStream),
],
);
}
Widget leftSection(text) {
return new Expanded(
child: new Container(
child: new Text(
text,
style: TextStyle(fontSize: 18),
),
),
);
}
Container rightSection(text, valueBoxStream) {
return new Container(
child: new Flexible(
flex: 1,
child: new TextField(
controller: textFieldController,
keyboardType: TextInputType.number,
textAlign: TextAlign.end,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter(new RegExp("[0-9.]")),
LengthLimitingTextInputFormatter(4),
],
decoration: new InputDecoration(
enabledBorder: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(15),
borderSide: new BorderSide(width: 1.2),
),
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(15),
borderSide: new BorderSide(color: Colors.lightBlueAccent),
),
hintText: '0.0',
),
onChanged: (val) {
valueBoxStream.add({'type': text, 'value': val});
},
),
),
);
}
}
我应该能够在这一点上得到Result: x.y
,但是我只在我改变textField一次并且在同一个'session'
之后才得到它
在此先感谢谁能真正向我解释为什么这不起作用以及我正在犯的错误。
我真的很抱歉..但是代码出现了很多问题,我甚至不确定从哪里开始。看起来你已经阅读了有关如何处理flutter状态的所有版本,并设法将它们组合在一个简单的用例中。这是一个工作示例修复:https://gitlab.com/hpoul/clinimetric/commit/413d32d4041f2e6adb7e30af1126af4b05e72271
我不知道如何回答这个“问题”,以便其他人可以从中受益。但..
我可能在这个列表中遗漏了很多东西。但这应该让你开始。看看我的变更集。它并不完美,但它确实有效。您应该尝试了解自己在做什么并降低复杂性,而不是将您找到的所有内容叠加在一起。