我已经使用 TextFormFields 和 DropdownButtons 构建了一个 Flutter 表单来编辑用户配置文件。初始值是使用 FutureBuilder 从 Firebase 调用的。下拉列表中的列表也是从 Firebase 流式传输的。
问题一:在DropdownButtons中,选择后initialvalues没有变化;Firebase 的值保留在表单中。但是,当您单击“保存”按钮时,它会正确更新 Firebase 的选择。如何覆盖初始值?我已经尝试了很多东西,但我假设这是一个州问题。
问题 2:如何向 DropdownButton 添加验证器以确保它不是空的?我不能让它工作。
太感谢了!
class EditProfilePage extends StatefulWidget {
const EditProfilePage({Key key, @required this.database, this.profile})
: super(key: key);
final FirestoreDatabase database;
final Profile profile;
static Future<void> show(
BuildContext context, {
FirestoreDatabase database,
Profile profile,
}) async {
await Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(
builder: (context) =>
EditProfilePage(database: database, profile: profile),
fullscreenDialog: true,
),
);
}
@override
_EditProfilePageState createState() => _EditProfilePageState();
}
class _EditProfilePageState extends State<EditProfilePage> {
final _formKey = GlobalKey<FormState>();
String userId;
String name;
String gender;
String relationshipStatus;
var _selectedGender;
var _selectedRelationshipStatus;
bool _validateAndSaveForm() {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 2.0,
title: Text('Edit Profile'),
),
body: _buildContents(),
backgroundColor: Colors.grey[200],
);
}
Widget _buildContents() {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: _buildForm(),
),
),
),
);
}
Widget _buildForm() {
return Form(
key: _formKey,
child: _buildFormChildren(),
);
}
Widget _buildFormChildren() {
final auth = Provider.of<AuthBase>(context, listen: false);
return FutureBuilder<DocumentSnapshot>(
future: FirebaseFirestore.instance
.collection('users')
.doc(auth.currentUser.uid)
.get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
_selectedGender = snapshot.data['gender'];
_selectedRelationshipStatus = snapshot.data['relationshipStatus'];
children = <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Name'),
initialValue: snapshot.data['name'],
validator: (value) =>
value.isNotEmpty ? null : 'Name can\'t be empty',
onSaved: (value) => name = value,
),
FormField(
initialValue: _selectedGender,
builder: (FormFieldState state) {
return InputDecorator(
decoration: InputDecoration(
labelText: 'Gender',
),
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('references')
.doc('profile_references')
.collection('gender')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return const Center(
child: const CircularProgressIndicator(),
);
var length = snapshot.data.docs.length;
DocumentSnapshot ds = snapshot.data.docs[length - 1];
return DropdownButton(
isDense: true,
value: _selectedGender,
hint: Text('Change to'),
items: snapshot.data.docs
.map((DocumentSnapshot document) {
return DropdownMenuItem(
value: document.data()['gender'],
child: Text(document.data()['gender']),
);
}).toList(),
onChanged: (value) {
setState(() {
gender = value;
_selectedGender = value;
});
},
);
}),
);
}),
FormField(
initialValue: _selectedRelationshipStatus,
builder: (FormFieldState state) {
return InputDecorator(
decoration: InputDecoration(
labelText: 'Relationship Status',
),
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('references')
.doc('profile_references')
.collection('relationshipStatus')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return const Center(
child: const CircularProgressIndicator(),
);
var length = snapshot.data.docs.length;
DocumentSnapshot ds = snapshot.data.docs[length - 1];
return DropdownButton(
isDense: true,
value: _selectedRelationshipStatus,
hint: Text('Change to'),
items: snapshot.data.docs
.map((DocumentSnapshot document) {
return DropdownMenuItem(
value: document.data()['relationshipStatus'],
child:
Text(document.data()['relationshipStatus']),
);
}).toList(),
onChanged: (value) {
setState(() {
relationshipStatus = value;
_selectedRelationshipStatus = value;
});
},
);
}),
);
}),
];
} else if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: SingleChildScrollView(
child: Column(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
SizedBox(height: 20),
RaisedButton(
color: Colors.green[100],
child: Text(
'Save',
style: TextStyle(fontSize: 18, color: Colors.black),
),
onPressed: () async {
if (_validateAndSaveForm()) {
try {
{
final profile = Profile(
name: name,
gender: gender,
relationshipStatus: relationshipStatus);
await widget.database.editProfile(profile);
Navigator.of(context).pop();
}
} on FirebaseException catch (e) {
showExceptionAlertDialog(
context,
title: 'Operation failed',
exception: e,
);
}
}
},
),
],
),
),
);
},
);
}
}