是否有一种方法可以使一些小部件基于Dart / Flutter上的下拉选择可见?



首先,我在编程方面相对较新,特别是在Dart/Flutter上,所以任何关于代码任何部分的提示都将非常感谢。

我的目标与此代码是创建一个页面的下拉菜单(命名为LabListDropdownMenu在代码中),其中包括一些城市的名称,然后,基于所选的城市,ListView应该只显示小部件(命名为LabInfoWidget在代码中)的实验室属于该城市。为了做到这一点,我试图通过使用布尔值来改变LabInfoWidget的可见性。

问题:我选择了DropdownMenu中的项目,它正确地改变了布尔值,但它似乎没有改变小部件的可见性。我找了很多地方,但我不知道我做错了什么。有人知道我在这里遗漏了什么吗?

谢谢你的帮助!

import 'package:flutter/material.dart';
import 'package:assistente_am/widgets/widgets.dart';
import 'package:maps_launcher/maps_launcher.dart';
import 'package:url_launcher/url_launcher.dart';
class LabList extends StatefulWidget {
@override
_LabListState createState() => _LabListState();
}
class _LabListState extends State<LabList> {
@override
Widget build(BuildContext context) {
return Assistente(
appBarTitle: 'Laboratory List',
menu: LabListBody(),
);
}
}
Map _cityBool = {
'City 1': isCityOne,
'City 2': isCityTwo,
'City 3': isCityThree,
};
var _cities = [
'City 1',
'City 2',
'City 3',
];
bool isCityOne = false;
bool isCityTwo = false;
bool isCityThree = false;
class LabListBody extends StatefulWidget {
@override
_LabListBodyState createState() => _LabListBodyState();
}
class _LabListBodyState extends State<LabListBody> {
@override
Widget build(BuildContext context) {
return Container(
decoration: backgroundGradient(),
child: ListView(
children: [
SizedBox(
height: 15,
),
Center(
child: DecoratedBox(
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 5.0, horizontal: 65.0),
child: LabListDropdownMenu(),
),
decoration: ShapeDecoration(
color: Colors.blue,
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1.0,
style: BorderStyle.solid,
color: Colors.cyan),
borderRadius: BorderRadius.circular(25.0)),
),
),
),
SizedBox(height: 15),
LabInfoWidget(
title: 'Lab 1',
address: 'Address 1',
schedule:
'Monday to Friday: 09h00 - 18h00nWeekends: Closed',
information: 'Only by car',
contact: ['1111111111'],
visibilityState: isCityOne,
),
LabInfoWidget(
title: 'Lab 2',
address: 'Address 2',
schedule:
'Monday to Thursday: 08h00 - 12h00nWeekends: 12h00 - 18h00',
information: 'Schedule by phone required',
contact: ['2222222222'],
visibilityState: isCityTwo
),
],
),
);
}
}
class LabInfoWidget extends StatefulWidget {
LabInfoWidget(
{this.title,
this.address,
this.schedule,
this.information,
this.contact,
this.visibilityState});
final String title;
final String address;
final String schedule;
final String information;
final List contact;
final bool visibilityState;
@override
_LabInfoWidgetState createState() => _LabInfoWidgetState();
}
class _LabInfoWidgetState extends State<LabInfoWidget> {
Padding textBox(String text, FontWeight fontWeight, double fontSize) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 0.0),
child: Text(
text,
style: TextStyle(fontWeight: fontWeight, fontSize: fontSize),
),
);
}
@override
Widget build(BuildContext context) {
return Visibility(
visible: widget.visibilityState,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
child: Center(
child: Container(
constraints: BoxConstraints(maxWidth: 400, maxHeight: 220),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 2.0, color: Colors.blue),
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: [
Text(
widget.title,
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
SizedBox(
height: 8,
),
Table(
columnWidths: {
1: FractionColumnWidth(0.7),
2: FractionColumnWidth(1)
},
children: [
TableRow(children: [
textBox('Schedule', FontWeight.bold, 14),
textBox(widget.schedule, FontWeight.normal, 14)
]),
TableRow(children: [
textBox('Info', FontWeight.bold, 14),
textBox(
widget.information, FontWeight.normal, 14)
]),
],
),
],
),
),
),
SizedBox(
width: 60,
child: Container(
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(15.0)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: () {
int call = widget.contact[0];
launch(('tel://$call'));
},
icon: Icon(
Icons.call,
color: Colors.white,
),
),
IconButton(
onPressed: () {
MapsLauncher.launchQuery(widget.address);
},
icon: Icon(
Icons.gps_fixed_sharp,
color: Colors.white,
),
)
],
),
),
)
],
),
),
),
),
),
);
}
}
// Menu Dropdown
class LabListDropdownMenu extends StatefulWidget {
@override
_LabListDropdownMenuState createState() => _LabListDropdownMenuState();
}
class _LabListDropdownMenuState extends State<LabListDropdownMenu> {
var _currentItemSelected;
@override
Widget build(BuildContext context) {
return DropdownButton<String>(
hint: Text(
'Choose the desired city',
style: TextStyle(color: Colors.white),
),
items: _cities.map((String dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
}).toList(),
onChanged: (String newValueSelected) {
setState(() {
this._currentItemSelected = newValueSelected;
_cityBool.forEach((key, value) => value = false);
_cityBool[newValueSelected] = true;
print("$newValueSelected set to true");
});
},
value: _currentItemSelected,
dropdownColor: Colors.blue,
style: TextStyle(color: Colors.white, fontSize: 18),
icon: Icon(
Icons.arrow_drop_down,
color: Colors.white,
),
);
}
}

主要问题是,你正在调用setState((){})方法上的onChanged处理DropdownButton,但这只重建LabListDropdownMenu小部件,所以LabListBody是永远不会被重建。

为了解决这个问题,你可以给LabListDropdownMenu传递一个回调函数。这样,当onChanged方法被触发时,你也可以调用这个回调来重建LabListBody。

用文字表达有点困难,所以我对你的代码做了一些编辑。我还对它做了一些其他的小编辑:

Map _cityBool = new Map();
var _cities = [
'City 1',
'City 2',
'City 3',
];
class LabList extends StatefulWidget {
@override
_LabListState createState() => _LabListState();
}
class _LabListState extends State<LabList> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Laboratory List')
),
body: LabListBody(),
);
}
}
class LabListBody extends StatefulWidget {
@override
_LabListBodyState createState() => _LabListBodyState();
}
class _LabListBodyState extends State<LabListBody> {
@override
void initState() {
_cities.forEach((element) {
_cityBool[element] = false;
});
super.initState();
}
@override
Widget build(BuildContext context) {
print("city bools array: ${_cityBool[_cities[0]]}, ${_cityBool[_cities[1]]}, ${_cityBool[_cities[2]]}");
return Container(
//decoration: backgroundGradient(),
child: ListView(
children: [
SizedBox(
height: 15,
),
Center(
child: DecoratedBox(
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 5.0, horizontal: 65.0),
child: LabListDropdownMenu(onDropdownChange: (String value) {
print("onDropdownChange $value");
setState(() {});
},
),
),
decoration: ShapeDecoration(
color: Colors.blue,
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1.0,
style: BorderStyle.solid,
color: Colors.cyan),
borderRadius: BorderRadius.circular(25.0)),
),
),
),
SizedBox(height: 15),
LabInfoWidget(
title: 'Lab 1',
address: 'Address 1',
schedule:
'Monday to Friday: 09h00 - 18h00nWeekends: Closed',
information: 'Only by car',
contact: ['1111111111'],
visibilityState: _cityBool[_cities[0]],
),
LabInfoWidget(
title: 'Lab 2',
address: 'Address 2',
schedule:
'Monday to Thursday: 08h00 - 12h00nWeekends: 12h00 - 18h00',
information: 'Schedule by phone required',
contact: ['2222222222'],
visibilityState: _cityBool[_cities[1]]
),
],
),
);
}
}
class LabInfoWidget extends StatefulWidget {
LabInfoWidget(
{this.title,
this.address,
this.schedule,
this.information,
this.contact,
this.visibilityState});
final String title;
final String address;
final String schedule;
final String information;
final List contact;
final bool visibilityState;
@override
_LabInfoWidgetState createState() => _LabInfoWidgetState();
}
class _LabInfoWidgetState extends State<LabInfoWidget> {
Padding textBox(String text, FontWeight fontWeight, double fontSize) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 0.0),
child: Text(
text,
style: TextStyle(fontWeight: fontWeight, fontSize: fontSize),
),
);
}
@override
Widget build(BuildContext context) {
return Visibility(
visible: widget.visibilityState,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
child: Center(
child: Container(
constraints: BoxConstraints(maxWidth: 400, maxHeight: 220),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 2.0, color: Colors.blue),
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: [
Text(
widget.title,
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
SizedBox(
height: 8,
),
Table(
columnWidths: {
1: FractionColumnWidth(0.7),
2: FractionColumnWidth(1)
},
children: [
TableRow(children: [
textBox('Schedule', FontWeight.bold, 14),
textBox(widget.schedule, FontWeight.normal, 14)
]),
TableRow(children: [
textBox('Info', FontWeight.bold, 14),
textBox(
widget.information, FontWeight.normal, 14)
]),
],
),
],
),
),
),
SizedBox(
width: 60,
child: Container(
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(15.0)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: () {
int call = widget.contact[0];
//launch(('tel://$call'));
},
icon: Icon(
Icons.call,
color: Colors.white,
),
),
IconButton(
onPressed: () {
//MapsLauncher.launchQuery(widget.address);
},
icon: Icon(
Icons.gps_fixed_sharp,
color: Colors.white,
),
)
],
),
),
)
],
),
),
),
),
),
);
}
}
// Menu Dropdown
class LabListDropdownMenu extends StatefulWidget {
final Function onDropdownChange;
LabListDropdownMenu({
@required this.onDropdownChange,
});
@override
_LabListDropdownMenuState createState() => _LabListDropdownMenuState();
}
class _LabListDropdownMenuState extends State<LabListDropdownMenu> {
var _currentItemSelected;
@override
Widget build(BuildContext context) {
return DropdownButton<String>(
hint: Text(
'Choose the desired city',
style: TextStyle(color: Colors.white),
),
items: _cities.map((String dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
}).toList(),
onChanged: (String newValueSelected) {
setState(() {
this._currentItemSelected = newValueSelected;
_cityBool.forEach((key, value) {
_cityBool.update(key, (value) => false);
});
//_cityBool.forEach((key, value) => value = false);
_cityBool[newValueSelected] = true;
});
widget.onDropdownChange(newValueSelected);
},
value: _currentItemSelected,
dropdownColor: Colors.blue,
style: TextStyle(color: Colors.white, fontSize: 18),
icon: Icon(
Icons.arrow_drop_down,
color: Colors.white,
),
);
}
}

最新更新