我希望能够编辑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
,但是在同一个'session'
中一次只更改一次textField之后,我只能得到一次。
预先感谢谁能真正向我解释为什么这不起作用以及我犯了什么错误。
答案 0 :(得分:0)
我真的很抱歉..但是该代码有很多错误,我什至不知道从哪里开始。您似乎已阅读了有关如何处理抖动状态的所有版本,并设法在一个简单的用例中将所有状态组合在一起。这是一个有效的示例修复:https://gitlab.com/hpoul/clinimetric/commit/413d32d4041f2e6adb7e30af1126af4b05e72271
我不确定如何回答这个“问题”,以便其他人可以从中受益。但是..
该列表中可能缺少很多东西。但这应该可以帮助您入门。看看我的零钱集。它不是完美的,但是有效。您应该尝试了解自己在做什么并降低复杂性,而不是将发现的所有内容堆叠在一起。