问题描述:
近期Flutter项目有个需求,根据后端传过来的数据,动态生成检查项目卡片,卡片中动态生成5个检查结果录入的TextField和一个结果判定的TextField,结果判定的TextField中的内容根据5个检查结果自动判定OK和NG,并将OK背景色设置为绿色,NG背景色设置为红色。但是,根据5个检查结果通过setState更新结果判定的TextField中的文本,内容更新后,背景色要键盘收起才会更新。
解决方案:
使用局部更新组件:ValueListenableBuilder
1、组件使用方式:
a、通过ValueNotifier设置变量changeFlag,ValueListenableBuilder通过观测此变量,一旦变量内容发生变化,则刷新对应的组件
final ValueNotifier<int> count = ValueNotifier<int>(0);
b、使用官方的 ValueListenableBuilder
组件进行包裹你需要更新状态的组件。它有两个参数,一个是监听的值,一个是渲染的组件,当这个值发生改变,就可以重新触发渲染组件的函数
ValueListenableBuilder(
valueListenable: changeFlag,
builder: (context, value, widget) {
return 组件;
},
)
c、改变changeFlag来更新组件
void _refreshComponent() {
changeFlag.value++;
}
2、项目实例:
a、初始化项目对象
List<Map<String, dynamic>> checkItem = [];
b、在initState中给checkItem赋值,实际项目从后端获取数据
@override
void initState() {
// TODO: implement initState
super.initState();
checkItem.add(
{
"insItem": "项目名称",
"insCondition": "检查规格",
"max": "10",//规格上限
"min": "0",//规格下限
"insUnit": "测量单位",
//五个检查录入格子控制器
"textEditControllers": [
new TextEditingController(),
new TextEditingController(),
new TextEditingController(),
new TextEditingController(),
new TextEditingController(),
],
//五个检查录入格子的状态,用来推断OK/NG
"textEditStatus": [
false,
false,
false,
false,
false,
],
//五个检查录入格子焦点
"focusNodes": [
new FocusNode(),
new FocusNode(),
new FocusNode(),
new FocusNode(),
new FocusNode(),
],
//判定格子的控制器
"judgeController": new TextEditingController(),
//通过来回切换true/false来触发组件刷新,防止键盘弹起时无法即使更新TextField的背景色
"refresh": ValueNotifier<bool>(true)
},
);
lastFocusNode = checkItem[2]["focusNodes"][4];
}
c、在dispose中释放focus
@override
void dispose() {
for (var item in checkItem) {
for (var focusNode in item["focusNodes"]) {
focusNode.dispose();
}
}
super.dispose();
}
d、组件使用
ValueListenableBuilder(
valueListenable: item["refresh"],
builder: (context, value, widget) {
return Row(
children: [
Text(
"判定:",
style: TextStyle(
fontSize: fontSize,
),
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
),
fillColor: item["judgeController"].text == "NG"
? Colors.red
: item["judgeController"].text == "OK"
? Color.fromRGBO(103, 194, 58, 1)
: Colors.white,
filled: true,//要使背景色生效必须设置为true
),
style: TextStyle(
fontSize: fontSize,
),
controller: item["judgeController"],
enabled: false,
),
),
Expanded(
child: Container(),
flex: 4,
)
],
);
})
/// description 根据检查结果修改判定状态
/// author JackMa
/// Date 2023/7/10 10:26
changeStatus(var item, setInnerState) {
//是否有异常
bool flag = false;
for (int i = 0; i < item["textEditStatus"].length; i++) {
if (item["textEditStatus"][i]) {
setInnerState(() {
item["judgeController"].text = "NG";
item["refresh"].value = !item["refresh"].value;
});
flag = true;
break;
}
}
if (!flag) {
//是否有空的判定格子
bool hasEmpty = false;
for (int i = 0; i < item["textEditControllers"].length; i++) {
if (item["textEditControllers"][i].text == "") {
setInnerState(() {
item["judgeController"].text = "";
item["refresh"].value = !item["refresh"].value;
});
hasEmpty = true;
break;
}
}
if (!hasEmpty) {
setInnerState(() {
item["judgeController"].text = "OK";
item["refresh"].value = !item["refresh"].value;
});
}
}
}