Я решил эту проблему, просто обновив SetModel
при изменении текста в текстовом поле. Основными компонентами являются методы updatePounds
и updateReps
, а также методы onChanged
в текстовых полях динамического виджета.
Я также позаботился о том, чтобы инициализировать контроллеры значениями, содержащимися вSetModel
при создании динамического виджета.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MaterialApp(
home: WorkoutStartScreen(),
));
}
class SetModel {
final int id;
int pounds;
int reps;
SetModel({
this.id,
this.pounds,
this.reps,
});
void updatePounds(int pounds) {
this.pounds = pounds;
}
void updateReps(int reps) {
this.reps = reps;
}
}
class WorkoutStartScreen extends StatefulWidget {
static const String routeName = "workoutStart";
@override
_WorkoutStartScreenState createState() => _WorkoutStartScreenState();
}
class _WorkoutStartScreenState extends State<WorkoutStartScreen> {
final List<SetModel> sets = [];
void _addSet() {
final id = sets.length;
setState(() {
sets.add(SetModel(id: id, pounds: 0, reps: 0));
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Workout tracker"),
centerTitle: true,
),
body: Container(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: sets.length,
itemBuilder: (BuildContext context, int index) {
return DynamicWidget(
set: sets[index],
pos: index + 1,
delete: () {
setState(() {
sets.removeAt(index);
});
},
);
},
),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _addSet(),
child: Icon(Icons.add),
),
);
}
}
class DynamicWidget extends StatelessWidget {
final TextEditingController poundsController = TextEditingController();
final TextEditingController repsController = TextEditingController();
final SetModel set;
final int pos;
final Function delete;
DynamicWidget({
Key key,
@required this.set,
@required this.pos,
@required this.delete,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
if (set.pounds != 0) {
poundsController.text = set.pounds.toString();
}
if (set.reps != 0) {
repsController.text = set.reps.toString();
}
return Container(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: Text(
"SET $pos",
),
),
SizedBox(width: 20.0),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: poundsController,
onChanged: (String pounds) {
set.updatePounds(int.parse(pounds));
},
keyboardType: TextInputType.number,
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
),
SizedBox(height: 10),
Text("pounds".toUpperCase()),
],
),
),
SizedBox(
width: 20,
),
Text("X"),
SizedBox(
width: 20,
),
Container(
width: size.width / 4,
child: Column(
children: <Widget>[
TextField(
controller: repsController,
onChanged: (String reps) {
set.updateReps(int.parse(reps));
},
keyboardType: TextInputType.number,
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
),
SizedBox(height: 10),
Text("reps".toUpperCase()),
],
),
),
SizedBox(width: 5.0),
IconButton(
icon: Icon(Icons.delete_forever),
onPressed: delete,
)
],
),
],
),
);
}
}
По сути, динамические виджеты перерисовываются каждый раз, когда вы вызываете setState
из его родителя. Поскольку вы никогда не указывали динамическим виджетам сохранять что-либо, они перерисовываются с нуля. Это все еще происходит, за исключением того, что теперь мы даем им некоторую начальную информацию.
Здесь - видео о том, как оно работает.