为什么 setState 不更新我的 UI 即使它改变了?
Why setState does not update my UI even it changes?
我无法理解为什么 setState 不起作用。因为它在 Stateful Widget 内部。不会有问题的。这是我的代码部分,您可以检查它。
class _MaintenanceScreenState extends State<MaintenanceScreen> {
final col = MostColors();
final colFr = FrenchColors();
final colCh = ChineseColors();
final api = MaintenanceApi();
var updateFormKey = GlobalKey<FormState>();
final List<TotalMaintenance>? maintenances = MaintenanceApi.totalMtncList;
List<TotalMaintenance>? _foundUsers = [];
late String notes;
DateFormat df= DateFormat('yyyy.MM.dd HH:mm:ss');
List<int>? statuses = [0, 1, 2, 3];
int? selectedStatus;
final List<int>? units = [0, 1, 2, 3];
int? selectedUnit;
Widget getTakeEvent(int index) {
return IconSlideAction(
caption: "İşleme Al",
color: colFr.frIcelandPoppy,
foregroundColor: Colors.white,
icon: Icons.update,
onTap: () async {
final resp = await api.takeEvent(
((selectedUnit==null || selectedUnit==3) && (selectedStatus==null || selectedStatus==3)
? _foundUsers : (selectedUnit!=null && selectedUnit!=3) && (selectedStatus==null || selectedStatus==3)
? _foundUsers?.where((element) => element.unitId==selectedUnit) :
(selectedUnit==null || selectedUnit==3) && (selectedStatus!=null && selectedStatus!=3)
? _foundUsers?.where((element) => element.status==selectedStatus) :
_foundUsers?.where((element) => element.unitId==selectedUnit && element.status==selectedStatus))?.toList()[index].id, LoginApi.userId,
LoginApi.userUnits[2].isExist == true ? 4 : 5, index);
resp.statusCode == 200 ? Fluttertoast
.showToast(
msg: "İşleme Alındı",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.TOP,
backgroundColor: colFr.frAuroraGreen,
textColor: CupertinoColors.white,
fontSize: 16.0) :
Fluttertoast.showToast(
msg: "İşleme Alınamadı",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.TOP,
backgroundColor: colFr.frTomatoRed,
textColor: CupertinoColors.white,
fontSize: 16.0);
_refresh();
},
);
}
...
@override
initState() {
_foundUsers = maintenances;
super.initState();
}
...
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Scaffold(
//when the keyboard opens, resizeToAvoidBottomInset prevents unnecessarily blank space. check the scaffold number. if facing more blank space that you expect, check the nested scaffold situation.
resizeToAvoidBottomInset: false,
backgroundColor: col.mostGreyAccent,
body: FutureBuilder<List<TotalMaintenance>>(
future: api.getTotalMaintenances(LoginApi.userId, widget.locId),
builder: (context, snapshot) {
if (snapshot.hasData) {
var filteredChoice = (selectedUnit==null || selectedUnit==3) && (selectedStatus==null || selectedStatus==3)
? _foundUsers : (selectedUnit!=null && selectedUnit!=3) && (selectedStatus==null || selectedStatus==3)
? _foundUsers?.where((element) => element.unitId==selectedUnit) :
(selectedUnit==null || selectedUnit==3) && (selectedStatus!=null && selectedStatus!=3)
? _foundUsers?.where((element) => element.status==selectedStatus) :
_foundUsers?.where((element) => element.unitId==selectedUnit && element.status==selectedStatus);
return RefreshWidget(
onRefresh: _refresh,
child: Column(
children: [
SizedBox(
width: width,
height: getDeviceType()=='phone' ? height*.13 : height*.14,
child: Container(
padding: EdgeInsets.only(left:16, top:height*.03, bottom: height*.01, right: 16),
color: col.mostPurple,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
CupertinoButton(
padding: EdgeInsets.fromLTRB(10,10,0,0),
child: Column(
children: [
Icon(CupertinoIcons.person_3_fill, color: CupertinoColors.white, size: width*.075,),
Text('Birimler', style: TextStyle(color: CupertinoColors.white),)
],
),
onPressed: () => {
showUnitPicker()
}
),
CupertinoButton(
padding: EdgeInsets.fromLTRB(10,10,0,0),
child: Column(
children: [
Icon(Icons.filter_list_alt, color: CupertinoColors.white, size: width*.075,),
Text('Durumlar', style: TextStyle(color: CupertinoColors.white),)
],
),
onPressed: () => {
showStatusPicker()
}
),
],
),
Row(
children: [
Text(
'Toplam Sorun: ${filteredChoice!.length} Adet\nİşleme Alınan Sorun: ${filteredChoice.where((element) => element.status==1).length} Adet\nÇözümlenen Sorun: ${filteredChoice.where((element) => element.status==2).length} Adet',
style: TextStyle(color: CupertinoColors.white, fontSize: getDeviceType()=='phone' ? width*.04 : width*.03),
textAlign: TextAlign.end,),
],
),
],
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: TextField(
onChanged: (value) => filteringBySearching(value),
cursorColor: col.mostDarkPurpleAccent,
style: TextStyle(color: col.mostDarkPurpleAccent),
decoration: const InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff3a2a6d)),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff3a2a6d)),
),
labelStyle: TextStyle(color: Color(0xff3a2a6d)),
labelText: 'Operatör Ara', suffixIcon: Icon(Icons.search, color: Color(0xff3a2a6d),)),
),
),
Expanded(
child: filteredChoice.isNotEmpty
? ListView.builder(
padding: EdgeInsets.all(8),
itemCount: filteredChoice.length,
itemBuilder: (context, index) => Card(
key: ValueKey(filteredChoice.toList()[index].id),
elevation: 4,
margin: const EdgeInsets.symmetric(vertical:2),
color: col.mostLightPurpleAccent,
child: Slidable(
actionPane: SlidableDrawerActionPane(),
actions: [
IconSlideAction(
caption: "Detaylar",
color: colFr.frFlatFresh,
foregroundColor: Colors.black,
icon: Icons.description,
onTap: () async {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) =>
MaintenanceLogScreen(userId:filteredChoice.toList()[index].userId, locId: widget.locId, maintenanceId: filteredChoice.toList()[index].id)));
}
)
],
secondaryActions: getSlidableButtons(filteredChoice.toList()[index].status!, index),
child: ListTile(
contentPadding: EdgeInsets.all(10),
leading: Container(
width: width * .15,
decoration: BoxDecoration(
color: col.mostDarkPurpleAccent,
borderRadius: BorderRadius.all(Radius.circular(10.0)),
shape: BoxShape.rectangle,
),
child: Center(
child: Text(
'${filteredChoice.toList()[index].equipmentCode!}',
textAlign: TextAlign.center,
style: TextStyle(color: CupertinoColors.white),
),
),
),
title: Container(
width: width * .7,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text( getDeviceType()=='phone' ?
"Açıklama: ${filteredChoice.toList()[index].description!}\nOluşturma:\n${df.format(DateTime.parse(filteredChoice.toList()[index].createdDate!.toString()))}\nGüncellenme:\n${df.format(DateTime.parse(filteredChoice.toList()[index].progressDate!.toString()))}":
"Açıklama: ${filteredChoice.toList()[index].description!}\nOluşturma: ${df.format(DateTime.parse(filteredChoice.toList()[index].createdDate!.toString()))}\nGüncellenme: ${df.format(DateTime.parse(filteredChoice.toList()[index].progressDate!.toString()))}",
textAlign: TextAlign.start,
style: TextStyle(fontSize: width*.0275),
),
Text("${filteredChoice.toList()[index].userName?.toLowerCase()}",
textAlign: TextAlign.end,
style: TextStyle(fontSize: width*.0275),)
],
)
),
trailing: Container(
width: width * .15,
child: Center(
child: iconPicker(filteredChoice.toList(), index, height)
),
),
),
),
)
)
: Center(
child: const Text(
'Aradığınız kriterlere uygun bakım bulunamadı.',
style: TextStyle(color: Color(0xff3a2a6d)),
)
)
),
],
),
);
}
else if(snapshot.data?.length==0) {
return Center(
child: Text("Bakım Bulunamadı.", style: TextStyle(fontSize: 16, color: Color(0xff3a2a6d))),
);
}
else {
_refresh();
return LoadingScreen();
}
}),
);
}
Future _refresh() async {
return api.getTotalMaintenances(LoginApi.userId, widget.locId).then((value) {
setState(() {
});
});
}
}
添加过滤后,它无法正常工作并且无法更新 UI。我无法理解的问题在哪里。有人可以帮助我吗?
您需要在 var filteredChoice=...
之前分配 _foundUsers= snapshot.data;
我无法理解为什么 setState 不起作用。因为它在 Stateful Widget 内部。不会有问题的。这是我的代码部分,您可以检查它。
class _MaintenanceScreenState extends State<MaintenanceScreen> {
final col = MostColors();
final colFr = FrenchColors();
final colCh = ChineseColors();
final api = MaintenanceApi();
var updateFormKey = GlobalKey<FormState>();
final List<TotalMaintenance>? maintenances = MaintenanceApi.totalMtncList;
List<TotalMaintenance>? _foundUsers = [];
late String notes;
DateFormat df= DateFormat('yyyy.MM.dd HH:mm:ss');
List<int>? statuses = [0, 1, 2, 3];
int? selectedStatus;
final List<int>? units = [0, 1, 2, 3];
int? selectedUnit;
Widget getTakeEvent(int index) {
return IconSlideAction(
caption: "İşleme Al",
color: colFr.frIcelandPoppy,
foregroundColor: Colors.white,
icon: Icons.update,
onTap: () async {
final resp = await api.takeEvent(
((selectedUnit==null || selectedUnit==3) && (selectedStatus==null || selectedStatus==3)
? _foundUsers : (selectedUnit!=null && selectedUnit!=3) && (selectedStatus==null || selectedStatus==3)
? _foundUsers?.where((element) => element.unitId==selectedUnit) :
(selectedUnit==null || selectedUnit==3) && (selectedStatus!=null && selectedStatus!=3)
? _foundUsers?.where((element) => element.status==selectedStatus) :
_foundUsers?.where((element) => element.unitId==selectedUnit && element.status==selectedStatus))?.toList()[index].id, LoginApi.userId,
LoginApi.userUnits[2].isExist == true ? 4 : 5, index);
resp.statusCode == 200 ? Fluttertoast
.showToast(
msg: "İşleme Alındı",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.TOP,
backgroundColor: colFr.frAuroraGreen,
textColor: CupertinoColors.white,
fontSize: 16.0) :
Fluttertoast.showToast(
msg: "İşleme Alınamadı",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.TOP,
backgroundColor: colFr.frTomatoRed,
textColor: CupertinoColors.white,
fontSize: 16.0);
_refresh();
},
);
}
...
@override
initState() {
_foundUsers = maintenances;
super.initState();
}
...
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Scaffold(
//when the keyboard opens, resizeToAvoidBottomInset prevents unnecessarily blank space. check the scaffold number. if facing more blank space that you expect, check the nested scaffold situation.
resizeToAvoidBottomInset: false,
backgroundColor: col.mostGreyAccent,
body: FutureBuilder<List<TotalMaintenance>>(
future: api.getTotalMaintenances(LoginApi.userId, widget.locId),
builder: (context, snapshot) {
if (snapshot.hasData) {
var filteredChoice = (selectedUnit==null || selectedUnit==3) && (selectedStatus==null || selectedStatus==3)
? _foundUsers : (selectedUnit!=null && selectedUnit!=3) && (selectedStatus==null || selectedStatus==3)
? _foundUsers?.where((element) => element.unitId==selectedUnit) :
(selectedUnit==null || selectedUnit==3) && (selectedStatus!=null && selectedStatus!=3)
? _foundUsers?.where((element) => element.status==selectedStatus) :
_foundUsers?.where((element) => element.unitId==selectedUnit && element.status==selectedStatus);
return RefreshWidget(
onRefresh: _refresh,
child: Column(
children: [
SizedBox(
width: width,
height: getDeviceType()=='phone' ? height*.13 : height*.14,
child: Container(
padding: EdgeInsets.only(left:16, top:height*.03, bottom: height*.01, right: 16),
color: col.mostPurple,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
CupertinoButton(
padding: EdgeInsets.fromLTRB(10,10,0,0),
child: Column(
children: [
Icon(CupertinoIcons.person_3_fill, color: CupertinoColors.white, size: width*.075,),
Text('Birimler', style: TextStyle(color: CupertinoColors.white),)
],
),
onPressed: () => {
showUnitPicker()
}
),
CupertinoButton(
padding: EdgeInsets.fromLTRB(10,10,0,0),
child: Column(
children: [
Icon(Icons.filter_list_alt, color: CupertinoColors.white, size: width*.075,),
Text('Durumlar', style: TextStyle(color: CupertinoColors.white),)
],
),
onPressed: () => {
showStatusPicker()
}
),
],
),
Row(
children: [
Text(
'Toplam Sorun: ${filteredChoice!.length} Adet\nİşleme Alınan Sorun: ${filteredChoice.where((element) => element.status==1).length} Adet\nÇözümlenen Sorun: ${filteredChoice.where((element) => element.status==2).length} Adet',
style: TextStyle(color: CupertinoColors.white, fontSize: getDeviceType()=='phone' ? width*.04 : width*.03),
textAlign: TextAlign.end,),
],
),
],
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: TextField(
onChanged: (value) => filteringBySearching(value),
cursorColor: col.mostDarkPurpleAccent,
style: TextStyle(color: col.mostDarkPurpleAccent),
decoration: const InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff3a2a6d)),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xff3a2a6d)),
),
labelStyle: TextStyle(color: Color(0xff3a2a6d)),
labelText: 'Operatör Ara', suffixIcon: Icon(Icons.search, color: Color(0xff3a2a6d),)),
),
),
Expanded(
child: filteredChoice.isNotEmpty
? ListView.builder(
padding: EdgeInsets.all(8),
itemCount: filteredChoice.length,
itemBuilder: (context, index) => Card(
key: ValueKey(filteredChoice.toList()[index].id),
elevation: 4,
margin: const EdgeInsets.symmetric(vertical:2),
color: col.mostLightPurpleAccent,
child: Slidable(
actionPane: SlidableDrawerActionPane(),
actions: [
IconSlideAction(
caption: "Detaylar",
color: colFr.frFlatFresh,
foregroundColor: Colors.black,
icon: Icons.description,
onTap: () async {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) =>
MaintenanceLogScreen(userId:filteredChoice.toList()[index].userId, locId: widget.locId, maintenanceId: filteredChoice.toList()[index].id)));
}
)
],
secondaryActions: getSlidableButtons(filteredChoice.toList()[index].status!, index),
child: ListTile(
contentPadding: EdgeInsets.all(10),
leading: Container(
width: width * .15,
decoration: BoxDecoration(
color: col.mostDarkPurpleAccent,
borderRadius: BorderRadius.all(Radius.circular(10.0)),
shape: BoxShape.rectangle,
),
child: Center(
child: Text(
'${filteredChoice.toList()[index].equipmentCode!}',
textAlign: TextAlign.center,
style: TextStyle(color: CupertinoColors.white),
),
),
),
title: Container(
width: width * .7,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text( getDeviceType()=='phone' ?
"Açıklama: ${filteredChoice.toList()[index].description!}\nOluşturma:\n${df.format(DateTime.parse(filteredChoice.toList()[index].createdDate!.toString()))}\nGüncellenme:\n${df.format(DateTime.parse(filteredChoice.toList()[index].progressDate!.toString()))}":
"Açıklama: ${filteredChoice.toList()[index].description!}\nOluşturma: ${df.format(DateTime.parse(filteredChoice.toList()[index].createdDate!.toString()))}\nGüncellenme: ${df.format(DateTime.parse(filteredChoice.toList()[index].progressDate!.toString()))}",
textAlign: TextAlign.start,
style: TextStyle(fontSize: width*.0275),
),
Text("${filteredChoice.toList()[index].userName?.toLowerCase()}",
textAlign: TextAlign.end,
style: TextStyle(fontSize: width*.0275),)
],
)
),
trailing: Container(
width: width * .15,
child: Center(
child: iconPicker(filteredChoice.toList(), index, height)
),
),
),
),
)
)
: Center(
child: const Text(
'Aradığınız kriterlere uygun bakım bulunamadı.',
style: TextStyle(color: Color(0xff3a2a6d)),
)
)
),
],
),
);
}
else if(snapshot.data?.length==0) {
return Center(
child: Text("Bakım Bulunamadı.", style: TextStyle(fontSize: 16, color: Color(0xff3a2a6d))),
);
}
else {
_refresh();
return LoadingScreen();
}
}),
);
}
Future _refresh() async {
return api.getTotalMaintenances(LoginApi.userId, widget.locId).then((value) {
setState(() {
});
});
}
}
添加过滤后,它无法正常工作并且无法更新 UI。我无法理解的问题在哪里。有人可以帮助我吗?
您需要在 var filteredChoice=...
之前分配_foundUsers= snapshot.data;