我正在设计一个带有文档列表的屏幕,我决定使用页眉上的ToggleButtons根据文档发布的年份来过滤文档。
文档的信息是从一个URL加载的,我用FutureBuilder来构建屏幕。当我点击一个ToggleButton时,setState不起作用,它不更新屏幕。我不知道为什么。
那样就不可能过滤文件了。
我分享代码:
class ListOfDocuments extends StatefulWidget {
final SingleItem singleItem;
final String sectionRowName;
const ListOfDocuments(
{Key? key, required this.singleItem, required this.sectionRowName})
: super(key: key);
@override
State<ListOfDocuments> createState() => _ListOfDocumentsState();
}
class _ListOfDocumentsState extends State<ListOfDocuments> {
// Iniciamos el servicio para pedir a la web la información.
final HttpService httpService = HttpService();
// Iniciamos la variable donde almacenaremos los documentos.
Future<List<Document>>? listadoDocumentos;
// Obtenemos el código del idioma utilizado.
String myLocale = Intl.getCurrentLocale();
// Cargamos documentos.
void cargarDocumentos() async {
// Pedimos el listado de documentos.
listadoDocumentos = httpService.getDocList(
myLocale.toString(),
widget.sectionRowName,
widget.singleItem,
);
}
@override
void initState() {
super.initState();
// Cargamos los documentos al iniciar.
cargarDocumentos();
}
@override
Widget build(BuildContext context) {
// Screen size.
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
// For ToggleButtons.
List<Widget> years = <Widget>[
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(S.of(context).all),
),
const Text("2005"),
const Text("2006"),
const Text("2007"),
const Text("2008"),
const Text("2009"),
const Text("2010"),
const Text("2011"),
const Text("2012"),
const Text("2013"),
];
List<bool> selectedYear = <bool>[
true,
false,
false,
false,
false,
false,
false,
false,
false,
false
];
return Scaffold(
backgroundColor: kPrimaryColor,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
centerTitle: true,
title: getTitle(widget.sectionRowName, widget.singleItem.name, context),
),
body: FutureBuilder(
future: listadoDocumentos,
builder: (BuildContext context, AsyncSnapshot snapshotFromList) {
if (snapshotFromList.hasData) {
// Hacemos una lista de titulos con fechas.
List<Document> docList = List.generate(
snapshotFromList.data.length,
(index) => Document(
id: snapshotFromList.data[index].id,
fecha: snapshotFromList.data[index].fecha,
titulo: snapshotFromList.data[index].titulo,
),
);
return Column(
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Padding(
padding: const EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 0.0),
child: ToggleButtons(
direction: Axis.horizontal,
textStyle: kAppBarStyle.copyWith(fontSize: 18.0),
borderColor: Colors.yellow,
borderWidth: 1.0,
selectedBorderColor: Colors.yellowAccent,
fillColor: Colors.yellowAccent.withOpacity(0.2),
color: Colors.white,
selectedColor: Colors.white,
isSelected: selectedYear,
borderRadius:
const BorderRadius.all(Radius.circular(10.0)),
onPressed: (int index) {
setState(() {
// The button that is tapped is set to true, and the others to false.
for (int i = 0; i < selectedYear.length; i++) {
selectedYear[i] = i == index;
}
});
},
children: years,
),
),
),
Expanded(
child: Padding(
padding:
EdgeInsets.fromLTRB(0.0, 0.0, screenWidth * 0.05, 0.0),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: ListView.separated(
itemCount: docList.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
separatorBuilder: (BuildContext context, int index) {
return const Divider(
thickness: 2.0,
color: Colors.white10,
indent: 15.0,
);
},
itemBuilder: (context, index) {
DateTime dateFormated = DateFormat('dd/MM/yyyy')
.parse(docList[index].fecha);
return ListTile(
leading: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Text(
DateFormat("dd").format(dateFormated),
style: kDocTitleInList.copyWith(
color: Colors.white70,
),
),
Text(
DateFormat("MMM")
.format(dateFormated)
.toUpperCase(),
style: kDocTitleInList.copyWith(
fontSize: 10.0,
color: Colors.white70,
),
),
Text(
DateFormat("yyyy").format(dateFormated),
style: kDocTitleInList.copyWith(
fontSize: 14.0,
color: Colors.white70,
),
),
],
),
title: Text(
docList[index].titulo,
style: kDocTitleInList,
),
trailing: const Icon(
Icons.arrow_forward_ios_rounded,
color: Colors.white,
),
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) {
return FutureBuilder(
// Pedimos a la web el documento por el "id".
future: httpService.getDocument(
snapshotFromList.data[index].id
.toString()),
builder: (BuildContext context,
AsyncSnapshot snapshotFromDocument) {
if (snapshotFromDocument.hasData) {
return Dialog(
backgroundColor: Colors.transparent,
elevation: 0.0,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.circular(30.0),
),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding:
const EdgeInsets.all(
15.0),
child: Text(
snapshotFromList
.data[index].titulo,
style: kSubTitleStyle
.copyWith(
color:
Colors.black),
),
),
Padding(
padding:
const EdgeInsets.all(
15.0),
child: FlagChips(
documento:
snapshotFromDocument
.data),
),
GestureDetector(
child: Text(
'- ${S.of(context).cerrarVentana} -',
style: kSubTitleStyle
.copyWith(
color:
Colors.black),
),
onTap: () {
Navigator.of(context)
.pop();
},
),
const SizedBox(
height: 20.0,
),
],
),
),
);
} else {
return const Center(
child: CircularProgressIndicator(
color: Colors.white54,
),
);
}
});
},
);
},
);
},
),
),
),
),
],
);
} else {
return const Center(
child: CircularProgressIndicator(
color: Colors.white54,
),
);
}
},
),
);
}
}
2条答案
按热度按时间unftdfkk1#
问题是
selectedYear
变量是在build
函数的作用域中声明的。因为这是有状态小部件的“状态”,所以应该在_ListOfDocumentsState
的主体中声明。只需将此变量移出build
,与httpService
、listadoDocumentos
和myLocale
变量放在一起。使用当前方法时,循环会按照您的意愿更新
selectedYear
列表,但是调用setState
会再次调用build
,这会将selectedYear
重置为原始状态,第一个元素为true
。s5a0g9ez2#
您可以在
Future
方法上定义它,并在button
上调用Future
方法。你也可以从
API
获取数据,如果你已经调用了setState
函数来重新加载你的状态。