вам нужно добавить значение ключа к вашим виджетам
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: Scaffold(body: Center(child: TestWidget())));
}
}
class MovableItem extends StatefulWidget {
final int removeIndex;
final double xInit;
final double yInit;
MovableItem({
Key key,
@required this.removeIndex,
@required this.xInit,
@required this.yInit,
}) : super(key: key);
@override
State<StatefulWidget> createState() {
return _MovableItemState();
}
}
class _MovableItemState extends State<MovableItem> {
double xPosition = 0;
double yPosition = 0;
double _height = 150;
double _width = 150;
@override
void initState() {
super.initState();
xPosition = widget.xInit;
yPosition = widget.yInit;
print('created: ${widget.removeIndex} with key ${widget.key}');
}
@override
Widget build(BuildContext context) {
return Positioned(
top: yPosition,
left: xPosition,
child: GestureDetector(
onPanUpdate: (DragUpdateDetails tapInfo) {
setState(() {
xPosition += tapInfo.delta.dx;
yPosition += tapInfo.delta.dy;
});
},
child: Row(
children: <Widget>[
GestureDetector(
child: Container(height: _height, width: _width, child: Text(widget.removeIndex.toString()))
),
],
),
),
);
}
@override
void dispose() {
super.dispose();
print('disposed: ${widget.removeIndex} with key ${widget.key}');
}
}
class TestWidget extends StatefulWidget {
TestWidgetState createState() => TestWidgetState();
}
class TestWidgetState extends State<TestWidget> {
List<Widget> _stack = [];
@override
void initState() {
super.initState();
_stack.add(MovableItem(key: Key('0'), removeIndex: 0, xInit: 0, yInit: 0,));
_stack.add(MovableItem(key: Key('1'), removeIndex: 1, xInit: 20, yInit: 20,));
}
void onChangedFunction(int removeIndex) {
setState(() {
_stack.removeAt(removeIndex);
});
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: <Widget>[
RaisedButton(
child: Text("remove 0 index"),
onPressed: () {
setState(() {
_stack.removeAt(0);
});
},),
SizedBox(
width: 500,
height: 500,
child: Stack(
children: _stack,
),
),
],
));
}
}
вывод консоли будет
created: 0 with key [<0>]
created: 1 with key [<1>]
disposed: 0 with key [<0>]
Почему это происходит? Когда вы устанавливаетеState и удаляете виджет с индексом 0, метод сборки перестраивает себя, и _stack больше не тот же объект, он проверяет, что список теперь имеет другую длину, и удаляет последние объекты (те, которые находятся за пределами новой длины). Если это нежелательно, вы должны добавить ключ к своим виджетам, чтобы при перестроении состояние знало, какой из них удалить на основе значения ключа.
Вы также можете проверить этот код, где я меняю значения печати, чтобы вы видели что происходит, когда вы устанавливаетеState и удаляете indexAt (0). didUpdateWidget изменяет и распечатывает различия между старым и новым, чтобы восстановить
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: Scaffold(body: Center(child: TestWidget())));
}
}
class MovableItem extends StatefulWidget {
final int removeIndex;
final double xInit;
final double yInit;
MovableItem({
@required this.removeIndex,
@required this.xInit,
@required this.yInit,
});
@override
State<StatefulWidget> createState() {
return _MovableItemState();
}
}
class _MovableItemState extends State<MovableItem> {
double xPosition = 0;
double yPosition = 0;
double _height = 150;
double _width = 150;
@override
void initState() {
super.initState();
xPosition = widget.xInit;
yPosition = widget.yInit;
print('created: ${widget.removeIndex}');
}
@override
void didUpdateWidget(MovableItem oldWidget){
print('updated: oldWidget ${oldWidget.removeIndex} vs newWidget ${widget.removeIndex}');
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return Positioned(
top: yPosition,
left: xPosition,
child: GestureDetector(
onPanUpdate: (DragUpdateDetails tapInfo) {
setState(() {
xPosition += tapInfo.delta.dx;
yPosition += tapInfo.delta.dy;
});
},
child: Row(
children: <Widget>[
GestureDetector(
child: Container(height: _height, width: _width, child: Text(widget.removeIndex.toString()))
),
],
),
),
);
}
@override
void dispose() {
super.dispose();
print('disposed: ${widget.removeIndex}');
}
}
class TestWidget extends StatefulWidget {
TestWidgetState createState() => TestWidgetState();
}
class TestWidgetState extends State<TestWidget> {
List<Widget> _stack = [];
@override
void initState() {
super.initState();
_stack.add(MovableItem(removeIndex: 0, xInit: 0, yInit: 0,));
_stack.add(MovableItem(removeIndex: 1, xInit: 20, yInit: 20,));
}
void onChangedFunction(int removeIndex) {
setState(() {
_stack.removeAt(removeIndex);
});
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: <Widget>[
RaisedButton(
child: Text("remove 0 index"),
onPressed: () {
setState(() {
_stack.removeAt(0);
});
},),
SizedBox(
width: 500,
height: 500,
child: Stack(
children: _stack,
),
),
],
));
}
}
Вывод консоли
created: 0
created: 1
updated: oldWidget 0 vs newWidget 1
disposed: 1
Без ключа создаются 2 объекта 0 и 1. Затем я удалил один с индексом 0 и перестроил родительский, дочерние элементы обновились, и теперь (без ключа) виджет с индексом 0 является единственным виджетом, и его значение обновляется с 0 до 1, а виджет с индексом 1 больше не существует ( потому что ваш список теперь имеет длину 1), поэтому он удален.
EDIT: Также, если вы хотите обновить все локальные параметры (xPosition и yPosition) без использования ключей, вы должны сделать это внутри метода didUpdateWidget
@override
void didUpdateWidget(MovableItem oldWidget){
print('updated: oldWidget ${oldWidget.removeIndex} vs newWidget ${widget.removeIndex}');
xPosition = widget.xInit;
yPosition = widget.yInit;
super.didUpdateWidget(oldWidget);
}
таким образом позиции обновятся, когда вы удалите один из виджетов из списка (если вы не хотите использовать ключи)