Как подавить поведение при прокрутке во Flutter?
У меня есть CustomScrollView
с SliverAppBar
что прячется на свитке.
На панели приложения есть кнопка поиска, при нажатии на которую появляется TextField
в панель приложения.
Когда поле получает фокус, это приводит к тому, что область прокрутки прокручивается до самого верха, а панель приложения застревает в "небезопасной" области:
В документах Scaffold упоминается, что, когда отображается клавиатура, вставки каркаса меняются, и каркас перестраивается, в результате чего "виджет с фокусом будет прокручен в поле зрения, если он находится в прокручиваемом контейнере".
Это похоже на поведение, которое я не хочу. Я смотрел, но не мог понять механизм или как его подавить. Возможно ли это?
Исходный код представления на изображении находится здесь.
Также отмечу, что этой проблемы не было в моей предыдущей реализации с нестандартными стандартными виджетами. Я подозреваю, что это потому, что панель приложения не была прокручиваемой, тогда какSliverAppBar
находится внутри CustomScrollView
так что он может взаимодействовать с основным телом.
2 ответа
Потребовалось некоторое расследование, но в конце концов я нашел механизм такого поведения.
TextField
обертывания EditableText
. Когда последний получит фокус, он вызовет _showCaretOnScreen
, который включает вызовrenderEditable.showOnScreen
. Это пузырится и в конечном итоге вызывает поведение прокрутки.
Мы можем заставить _showCaretOnScreen
вернуться сюда раньше, если мы поставимTextField
взломанный ScrollController
что всегда возвращается false
от hasClients
:
class _HackScrollController extends ScrollController {
// Causes early return from EditableText._showCaretOnScreen, preventing focus
// gain from making the CustomScrollView jump to the top.
@override
bool get hasClients => false;
}
Такое поведение не кажется преднамеренным, поэтому я сообщил об этом как об ошибке № 60422.
Предостережения
Этот обходной путь может быть не очень стабильным.
Я не знаю, какие побочные эффекты hasClients
переопределение могло иметь.
В документах дляTextField
сказать, что scrollController
используется "при вертикальной прокрутке ввода". В этом случае нам все равно не нужна вертикальная прокрутка, поэтому обходной путь может не вызвать никаких проблем. В моем кратком тестировании, похоже, проблем с горизонтальной прокруткой (переполнением) не возникало.
Как и в документации, попробуйте использовать параметр resizeToAvoidBottomInset со значением false (по умолчанию - true) в виджете scaffold https://api.flutter.dev/flutter/material/Scaffold/resizeToAvoidBottomInset.html
Также я бы рекомендовал создать ValueListenableBuilder после каркаса (как первый виджет в теле), чтобы не перестраивать весь каркас и только виджет тела.