Контекст:
Я наткнулся на небольшой сбой во время тестирования ListView
из Dismissible
s во Флаттере. При смахивании запрещается, Dialog
отображается с использованием опции confirmDismiss
, для подтверждения. Это все работает хорошо, однако пользовательский интерфейс падает при тестировании маловероятного варианта использования. На странице есть несколько вариантов навигации по другим (именованным) маршрутам. Когда запрещается движение, и во время анимации выбирается опция для перехода на новый маршрут, происходит сбой.
Как воспроизвести сбой:
- Отклонить от делимого
- Во время следующей анимации (перевод положения недопустимого) нажмите на действие, которое приведет вас к
новый маршрут. Временные рамки для этого минимальны, я увеличил их в примере.
- Новый маршрут загружается и пользовательский интерфейс останавливается
Для справки это сообщение об ошибке:
AnimationController.reverse () вызывается после AnimationController.dispose ()
Виновником является анимация, которая пытается повернуть вспять, когда она уже была уничтожена:
Пакет: трепетание / ... / виджеты / dismissible.dart: 449
Вещи, которые я пробовал:
Сначала я попытался проверить this.mounted
внутри showDialog builder
, но быстро понял, что проблема не в этом.
Другая идея состояла в том, чтобы обойти проблему с помощью CancelableOperation.fromFuture
и затем отменить ее в методе dispose()
охватывающего виджета, но это было бесполезно.
Что я могу решить или, по крайней мере, обойти эту проблему?
Код (также можно найти и клонировать здесь ):
// (...)
class _DimissibleListState extends State<DimissibleList> {
int childSize = 3;
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: childSize,
itemBuilder: (context, index) {
if (index == 0) {
return _buildNextPageAction(context);
}
return _buildDismissible();
},
),
);
}
Widget _buildNextPageAction(context) {
return FlatButton(
child: Text("Go to a new page"),
onPressed: () => Navigator.of(context).pushNamed('/other'),
);
}
Dismissible _buildDismissible() {
GlobalKey key = GlobalKey();
return Dismissible(
key: key,
child: ListTile(
title: Container(
padding: const EdgeInsets.all(8.0),
color: Colors.red,
child: Text("A dismissible. Nice."),
),
),
confirmDismiss: (direction) async {
await Future.delayed(const Duration(milliseconds: 100), () {});
return showDialog(
context: context,
builder: (context) {
return Dialog(
child: FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text("Confirm dismiss?"),
),
);
},
);
},
resizeDuration: null,
onDismissed: (direction) => setState(() => childSize--),
);
}
}