我正在嘗試為自己創建一個培訓應用程式。我創建了一個可以在每次按下按鈕時添加更多文本欄位的應用程式。我遇到的問題是所有欄位都有相同的值,我不能輸入兩個不同的
我已經嘗試了幾件事,最接近的是當我可以做不同的值但不能保存它時。

我的代碼如下:
class EventEditingPage extends StatefulWidget {
final Event? event;
const EventEditingPage({Key? key, this.event}) : super(key: key);
@override
_EventEditingPageState createState() => _EventEditingPageState();
}
class _EventEditingPageState extends State<EventEditingPage> {
final _formKey = GlobalKey<FormState>();
final setsController = TextEditingController();
final repsController = TextEditingController();
final loadController = TextEditingController();
late DropdownButton Exercise;
@override
void initState() {
super.initState();
final event = widget.event!;
exercise = event.Exercise;
setsController.text = event.Sets;
repsController.text = event.Reps;
loadController.text = event.Load;
}
}
@override
void dispose() {
setsController.dispose();
repsController.dispose();
loadController.dispose();
super.dispose();
}
int numberOfTextFields = 1;
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
leading: CloseButton(),
actions: buildEditingActions(),
backgroundColor: Colors.red,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("text", style: TextStyle(fontSize: 24)),
SizedBox(height: 12),
Text("\ntext", style: TextStyle(fontSize: 24)),
for(int i = 0 ; i < numberOfTextFields ; i )
buildExerciseComplete(),
buildAddMore(),
],
),
),
),
);
List<Widget> buildEditingActions() => [
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
primary: Colors.transparent, shadowColor: Colors.transparent),
onPressed: saveForm,
icon: Icon(Icons.done),
label: Text('Save'),
)
];
Widget buildExerciseComplete() => Container(
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Color.fromARGB(255, 255, 200, 200),
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
width: 2.0,
),
),
height: 50,
child: Row(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(child: buildExercise()),
Expanded(child: buildSets()),
Expanded(child: buildReps()),
Expanded(child: buildLoad()),
],
),
),
],
),
);
Widget buildSets() => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: TextStyle(fontSize: 15),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Sets',
),
onFieldSubmitted: (_) => saveForm,
validator: (sets) =>
sets != null && sets.isEmpty ? 'Sets cannot be empty' : null,
controller: setsController,
);
Widget buildReps() => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: TextStyle(fontSize: 15),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Reps',
),
onFieldSubmitted: (_) => saveForm,
validator: (reps) =>
reps != null && reps.isEmpty ? 'Reps cannot be empty' : null,
controller: repsController,
);
Widget buildLoad() => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: TextStyle(fontSize: 15),
decoration: InputDecoration(
labelText: 'Load',
border: OutlineInputBorder(),
),
onFieldSubmitted: (_) => saveForm,
validator: (load) =>
load != null && load.isEmpty ? 'Load cannot be empty' : null,
controller: loadController,
);
String exercise = 'Squat';
Widget buildExercise() => DropdownButton<String>(
value: exercise,
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
style: const TextStyle(color: Colors.black),
onChanged: (String? newValue) {
setState(() {
exercise = newValue!;
});
},
items: <String>['Squat', 'Deadlift', 'Bench']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
Widget buildAddMore() => ElevatedButton(
onPressed: () {
setState((){
numberOfTextFields ;
_textEditingControllers.add(TextEditingController());
});
},
child: Text('Add new exercise'),
);
Future saveForm() async {
final isValid = _formKey.currentState!.validate();
if (isValid) {
final event = Event(
Exercise: exercise,
Sets: setsController.text,
Reps: repsController.text,
Load: loadController.text);
final isEditing = widget.event != null;
final provider = Provider.of<EventProvider>(context, listen: false);
if (isEditing) {
provider.editEvent(event, widget.event!);
Navigator.of(context).pop();
} else {
provider.addEvent(event);
}
Navigator.of(context).pop();
}
}
}
class Event {
final Exercise;
final String Sets;
final String Reps;
final String Load;
final Color backgroundColor;
const Event({
required this.Sets,
required this.Reps,
required this.Load,
this.backgroundColor = Colors.lightGreen,
});
}
我很漂亮,原因與 TextEditingController() 有關
我希望有人可以幫助我解決我的問題:-)
uj5u.com熱心網友回復:
似乎您正在使用相同的控制器構建所有欄位,因此所有欄位都將具有相同的值。您應該列出控制器并添加控制器。
像這樣宣告變數:
final List<TextEditingController> setsController = [];
final List<TextEditingController> repsController = [];
final List<TextEditingController> loadController = [];
然后創建控制器:
createControllers() {
for (var i = 0; i < numberOfTextFields; i ) {
setsController.add(TextEditingController());
repsController.add(TextEditingController());
loadController.add(TextEditingController());
}
}
在相應的文本欄位中使用控制器:
controller: repsController[index]
在 initState() 呼叫創建控制器方法。

我想你可以從這里處理控制器的值檢索和處置。
我不知道你的保存邏輯,所以我把它注釋掉了。
class _EventEditingPageState extends State<EventEditingPage> {
final _formKey = GlobalKey<FormState>();
final List<TextEditingController> setsController = [];
final List<TextEditingController> repsController = [];
final List<TextEditingController> loadController = [];
// late DropdownButton Exercise;
List<String> exceriseItems = ['Squat', 'Deadlift', 'Bench'];
List<String> selectedExercise = [];
int numberOfTextFields = 1;
@override
void initState() {
super.initState();
final event = widget.event!;
createControllers();
selectedExercise[0] = event.Exercise != "" ? event.Exercise : exceriseItems[0];
setsController[0].text = event.Sets;
repsController[0].text = event.Reps;
loadController[0].text = event.Load;
}
@override
void dispose() {
setsController.forEach((TextEditingController element) {
element.dispose();
});
// Or simply clear the array.
// todo : repsController dispose();
// todo : loadController dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
leading: const CloseButton(),
actions: buildEditingActions(),
backgroundColor: Colors.red,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text("text", style: TextStyle(fontSize: 24)),
const SizedBox(height: 12),
const Text("\ntext", style: TextStyle(fontSize: 24)),
for (int i = 0; i < numberOfTextFields; i )
buildExerciseComplete(i),
buildAddMore(),
],
),
),
),
);
List<Widget> buildEditingActions() => [
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
primary: Colors.transparent, shadowColor: Colors.transparent),
onPressed: saveForm,
icon: const Icon(Icons.done),
label: const Text('Save'),
)
];
Widget buildExerciseComplete(int idx) => Container(
padding: const EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 255, 200, 200),
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
width: 2.0,
),
),
height: 50,
child: Row(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(child: buildExercise(idx)),
Expanded(child: buildSets(idx)),
Expanded(child: buildReps(idx)),
Expanded(child: buildLoad(idx)),
],
),
),
],
),
);
Widget buildSets(int idx) => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: const TextStyle(fontSize: 15),
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Sets',
),
onFieldSubmitted: (_) => saveForm,
validator: (sets) =>
sets != null && sets.isEmpty ? 'Sets cannot be empty' : null,
controller: setsController[idx],
);
Widget buildReps(int idx) => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: const TextStyle(fontSize: 15),
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Reps',
),
onFieldSubmitted: (_) => saveForm,
validator: (reps) =>
reps != null && reps.isEmpty ? 'Reps cannot be empty' : null,
controller: repsController[idx],
);
Widget buildLoad(int idx) => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: const TextStyle(fontSize: 15),
decoration: const InputDecoration(
labelText: 'Load',
border: const OutlineInputBorder(),
),
onFieldSubmitted: (_) => saveForm,
validator: (load) =>
load != null && load.isEmpty ? 'Load cannot be empty' : null,
controller: loadController[idx],
);
Widget buildExercise(int idx) => DropdownButton<String>(
value: selectedExercise[idx],
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
style: const TextStyle(color: Colors.black),
onChanged: (String? newValue) {
setState(() {
selectedExercise[idx] = newValue!;
});
},
items: exceriseItems
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
Widget buildAddMore() => ElevatedButton(
onPressed: () {
setState(() {
numberOfTextFields ;
createControllers();
});
},
child: const Text('Add new exercise'),
);
createControllers() {
for (var i = 0; i < numberOfTextFields; i ) {
setsController.add(TextEditingController());
repsController.add(TextEditingController());
loadController.add(TextEditingController());
}
selectedExercise.add(exceriseItems[0]);
}
Future saveForm() async {
final isValid = _formKey.currentState!.validate();
if (isValid) {
// final event = Event(
// Exercise: exercise,
// Sets: setsController.text,
// Reps: repsController.text,
// Load: loadController.text);
final isEditing = widget.event != null;
// final provider = Provider.of<EventProvider>(context, listen: false);
// if (isEditing) {
// provider.editEvent(event, widget.event!);
//
// Navigator.of(context).pop();
// } else {
// provider.addEvent(event);
// }
//
// Navigator.of(context).pop();
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/490343.html
