Flutter: CupertinoPicker BottomSheet слушатель для onClose?
Я просматриваю галерею флаттера для кода, связанного с CupertinoPicker.
Вот соответствующая выдержка из кода:
child: new GestureDetector(
// Blocks taps from propagating to the modal sheet and popping.
// onTap: () { },
child: new SafeArea(
child: new CupertinoPicker(
scrollController: scrollController,
itemExtent: _kPickerItemHeight,
backgroundColor: CupertinoColors.white,
onSelectedItemChanged: (int index) {
setState(() {
print(_selectedItemIndex);
_selectedItemIndex = index;
});
},
children: new List<Widget>.generate(coolColorNames.length, (int index) {
return new Center(child:
new Text(coolColorNames[index]),
);
}),
),
),
),
Теперь мне нужен обратный вызов / прослушиватель, когда CupertinoPicker закрывается, иными словами, когда пользователь сделал свой выбор и его выбор окончательный, мне нужно знать, каков его окончательный выбор.
В данном случае я хочу сделать обратный вызов API на основе его окончательного выбора, когда нижняя таблица закрывается.
На данный момент я могу получить только значения, так как пользователь запускает сборщик, поскольку для onSelectedItemChanged существует только обратный вызов. Смотрите GIF ниже.
Я вижу, что виджет BottomSheet имеет обратный вызов onClosing: https://docs.flutter.io/flutter/material/BottomSheet-class.html
Но я не совсем понимаю, как заставить его использовать, так как образец галереи Flutter вызывает нижний лист с использованием следующего кода, и нет способа получить нижний лист из кода:
new GestureDetector(
onTap: () async {
await showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return _buildBottomPicker();
},
);
},
child: _buildMenu(),
),
Кто-нибудь знает, как я могу получить прослушиватель обратного вызова для этого?
РЕДАКТИРОВАТЬ - Основываясь на решении Remi, я добавил код Navigator.of(context).pop(value) в обратный вызов onTap. Однако CupertinoPicker не является постоянным, поэтому, если пользователь прикасается к внешнему средству выбора, средство выбора закрывается, и возвращается нулевое значение:
Widget _buildBottomPicker() {
final FixedExtentScrollController scrollController =
new FixedExtentScrollController(initialItem: _selectedItemIndex);
return new Container(
height: _kPickerSheetHeight,
color: CupertinoColors.white,
child: new DefaultTextStyle(
style: const TextStyle(
color: CupertinoColors.black,
fontSize: 22.0,
),
child: new GestureDetector(
// Blocks taps from propagating to the modal sheet and popping.
onTap: () { Navigator.of(context).pop(_selectedItemIndex);},
child: new SafeArea(
child: new CupertinoPicker(
scrollController: scrollController,
itemExtent: _kPickerItemHeight,
backgroundColor: CupertinoColors.white,
onSelectedItemChanged: (int index) {
setState(() {
// print(_selectedItemIndex);
// Navigator.of(context).pop(index);
_selectedItemIndex = index;
});
},
children: new List<Widget>.generate(coolColorNames.length, (int index) {
return new Center(child:
new Text(coolColorNames[index]),
);
}),
),
),
),
),
);
}
4 ответа
На самом деле это намного проще, чем вы думали.
showDialog
и это аналоги (в том числе showModalBottomSheet
) возвращает Future
который содержит результат. Таким образом, вы можете сделать следующее:
final selectedId = await showModalBottomSheet<int>(...);
Единственное требование заключается в том, что при открытии модального / диалогового / маршрутного / любого другого, вы делаете Navigator.of(context).pop(value)
чтобы отправить это значение.
Как и в предыдущем ответе, нужное вам значение возвращается в форме будущего. Хотя это правда, мне не было очевидно, как это реализовать. В моем случае я хотел отфильтровать список задач по списку категорий на том же экране. Таким образом, используя ключ int, возвращаемый onSelectedItemChanged, я смог фильтровать вот так...
Widget _buildCategoryPicker(BuildContext context, _todoBloc) {
final FixedExtentScrollController scrollController =
FixedExtentScrollController(initialItem: _selectedIndex);
return GestureDetector(
onTap: () async {
await showCupertinoModalPopup<String>(
context: context,
builder: (BuildContext context) {
return _buildBottomPicker(
CupertinoPicker(
(...)
onSelectedItemChanged: (int index) {
setState(() => _selectedIndex = index);
},
children: (...),
), // CupertinoPicker
);
},
); // await showCupertinoModalPopup
// Filters the todoList.
_todoBloc.filter.add(categories[_selectedIndex]);
},
child: _buildMenu(
...
),
);
}
Вам не нужно устанавливать финал для вашего showCupertinoModalPopup или чего-то подобного...
final selectedId = await showCupertinoModalPopup<String>(...);
showModalBottomSheet(
context: context,
builder: (_) {
return GestureDetector(
onTap: () => Navigator.of(context).pop(), // closing showModalBottomSheet
child: FlutterLogo(size: 200),
);
},
);