无法更改下拉按钮值颤振
Posted
技术标签:
【中文标题】无法更改下拉按钮值颤振【英文标题】:Cannot change Dropdown button value Flutter 【发布时间】:2021-10-24 06:30:39 【问题描述】:我想从 firebase 获取 Dropdown 按钮的初始值;
但是当我尝试在构建方法中设置governorateDDValue = selectedUser.governorate;
Dropdown 的值从 firebase 获取值,但我无法更改它
DropdownButton.gif
这是我的代码
class UserInfo extends StatefulWidget
static const routeName = '/UserInfoScreen';
const UserInfo(Key? key) : super(key: key);
@override
_UserInfoState createState() => _UserInfoState();
class _UserInfoState extends State<UserInfo>
late User selectedUser;
final date = DateFormat('yyyy-MM-dd').format(DateTime.now()).toString();
var governorateDDValue;
@override
Widget build(BuildContext context)
final userList= Provider.of<List<User>>(context);
final userID = ModalRoute.of(context)!.settings.arguments as String;
selectedUser =
userList.firstWhere((user) => user.id == userID);
// this line makes dropdown value always equal to value from firestore
governorateDDValue = selectedUser.governorate;
return Scaffold(
appBar: AppBar(
title: Text('report'),
),
body: SingleChildScrollView(
child: Container(
child: Row(
children: <Widget>[
Text('Governorate',),
Container(height: 5),
DropdownButton<String>(
value: governorateDDValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
onChanged: (String? newValue)
setState(()
governorateDDValue = newValue!;
);
,
items: Constants.governoratesOfEgypt
.map<DropdownMenuItem<String>>((String value)
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
).toList(),
),
],
),
),
),
);
提前致谢
【问题讨论】:
【参考方案1】:因为您在构建小部件中使用governorateDDValue = selectedUser.governorate;
,所以每次更改下拉菜单时都会重置其值
构建小部件将重建,下拉列表的值将保持等于 firebase 的值
您应该在构建小部件之外使用governorateDDValue = selectedUser.governorate;
这段代码应该可以工作
class UserInfo extends StatefulWidget
static const routeName = '/UserInfoScreen';
const UserInfo(Key? key) : super(key: key);
@override
_UserInfoState createState() => _UserInfoState();
class _UserInfoState extends State<UserInfo>
var loading = false;
late User selectedUser;
final date = DateFormat('yyyy-MM-dd').format(DateTime.now()).toString();
var governorateDDValue;
@override
void initState()
super.initState();
loading = true;
print('Future.delayed outside');
print(loading);
Future.delayed(Duration.zero, ()
governorateDDValue = selectedUser.governorate;
setState(()
loading = false;
);
);
@override
Widget build(BuildContext context)
final userList = Provider.of<List<User>>(context);
final userID = ModalRoute
.of(context)!
.settings
.arguments as String;
selectedUser =
userList.firstWhere((user) => user.id == userID);
// this line makes dropdown value always equal to value from firestore
governorateDDValue = selectedUser.governorate;
return Scaffold(
appBar: AppBar(
title: Text('report'),
),
body: SingleChildScrollView(
child: Container(
child: Row(
children: <Widget>[
Text('Governorate',),
Container(height: 5),
DropdownButton<String>(
value: governorateDDValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
onChanged: (String? newValue)
setState(()
governorateDDValue = newValue!;
);
,
items: Constants.governoratesOfEgypt
.map<DropdownMenuItem<String>>((String value)
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
).toList(),
),
],
),
),
),
);
【讨论】:
【参考方案2】:之所以不能更改它是因为每次调用setState
时都会调用您的build
方法。因此,您的值将始终设置为 governorateDDValue = selectedUser.governorate;
所以要允许更改,您应该将此 governorateDDValue = selectedUser.governorate;
放在 iniState
中
或者你可以这样做,这样它只会设置一次
class UserInfo extends StatefulWidget
static const routeName = '/UserInfoScreen';
const UserInfo(Key? key) : super(key: key);
@override
_UserInfoState createState() => _UserInfoState();
class _UserInfoState extends State<UserInfo>
late User selectedUser;
final date = DateFormat('yyyy-MM-dd').format(DateTime.now()).toString();
bool initState = true; // ADD HERE
var governorateDDValue;
@override
Widget build(BuildContext context)
final userList= Provider.of<List<User>>(context);
final userID = ModalRoute.of(context)!.settings.arguments as String;
selectedUser =
userList.firstWhere((user) => user.id == userID);
// this line makes dropdown value always equal to value from firestore
if(initState) // ADD HERE
governorateDDValue = selectedUser.governorate;
initState = false; // ADD HERE
return Scaffold(
appBar: AppBar(
title: Text('report'),
),
body: SingleChildScrollView(
child: Container(
child: Row(
children: <Widget>[
Text('Governorate',),
Container(height: 5),
DropdownButton<String>(
value: governorateDDValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
onChanged: (String? newValue)
setState(()
governorateDDValue = newValue!;
);
,
items: Constants.governoratesOfEgypt
.map<DropdownMenuItem<String>>((String value)
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
).toList(),
),
],
),
),
),
);
【讨论】:
我把这个governanceDDValue = selectedUser.governorate;在 iniState 它给了我这个错误 LateInitializationError: Field 'selectedUser' has not been initialized。当我删除“selectedUser = userList.firstWhere((user) => user.id == userID);”到 initState 它给了我另一个错误在构建 Builder 时抛出了以下断言:在 _UserInfoState.initState() 完成之前调用了dependOnInheritedWidgetOfExactType<_modalscopestatus>() 或dependOnInheritedElement()。 您必须将所有逻辑移动到 iniState 中,如果您需要提供者的上下文,您可以使用didChangeDependencies
我已经编辑了答案以获得更简单的解决方案以上是关于无法更改下拉按钮值颤振的主要内容,如果未能解决你的问题,请参考以下文章
选择值时出现颤振下拉按钮错误[使用来自 api 和 FutureBuilder 的数据]