Как подавить поведение прокрутки во Flutter?

У меня есть CustomScrollView с SliverAppBar, который скрывается при прокрутке.

На панели приложений есть кнопка поиска, при нажатии на которую появляется TextField на панели приложений.

Когда поле получает фокус, представление прокрутки прокручивается до самого верха, а панель приложения застревает в небезопасной области:

прокрутить фокус

Scaffold docs упомяните, что когда отображается клавиатура, вставки каркаса меняются, а каркас перестраивается, в результате чего сфокусированный виджет будет прокручиваться в поле зрения, если он находится в прокручиваемом контейнере.

Это похоже на поведение, которое я не хочу. Я смотрел, но не мог понять ни механизма, ни того, как его подавить. Возможно ли это?

Исходный код представления на изображении: здесь.

Также я отмечаю, что этой проблемы не было в моей предыдущей реализации со стандартными виджетами без щепок. Я подозреваю, что это связано с тем, что панель приложения не была прокручиваемой, тогда как SliverAppBar находится внутри CustomScrollView, чтобы она могла взаимодействовать с основным телом.


person Aaron    schedule 25.06.2020    source источник
comment
Не уверен, что это решит проблему, но попробуйте создать панель приложений с помощью floating: true, pinned: true, snap: true . Ссылка на документ   -  person dev-aentgs    schedule 25.06.2020
comment
Я не хочу, чтобы он был закреплен, поэтому, даже если бы это решило проблемы с прокруткой и/или безопасной областью, это все равно не решило бы мою проблему.   -  person Aaron    schedule 25.06.2020
comment
Ok. просто спрашиваю, установка pinned: false, снова вызывает проблему с прокруткой/SafeArea?   -  person dev-aentgs    schedule 25.06.2020
comment
На гифке выше показан случай pinned: false. Случай pinned: true держит панель приложения заблокированной в нужном месте, но содержимое под ней все еще прокручивается, и оно прокручивается с немного неправильным смещением (немного перекрывается полосой).   -  person Aaron    schedule 26.06.2020


Ответы (2)


Редактировать: эта проблема была исправлена ​​этим PR, который, по-видимому, появился первым во флаттере 1.22.0.

Потребовалось некоторое расследование, но в конце концов я нашел механизм такого поведения.

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 используется при вертикальной прокрутке страницы. вход. В этом случае нам все равно не нужна вертикальная прокрутка, поэтому обходной путь может не вызвать никаких проблем. В моем кратком тестировании не было проблем с горизонтальной прокруткой (переполнением).

person Aaron    schedule 27.06.2020

Так же, как в документации упоминается, попробуйте использовать для параметра resizeToAvoidBottomInset значение false (по умолчанию — true) в виджете шаблона https://api.flutter.dev/flutter/material/Scaffold/resizeToAvoidBottomInset.html

Также я бы порекомендовал создать ValueListenableBuilder после каркаса (как первый виджет в теле), чтобы избежать перестроения всего каркаса и только виджета тела.

person EdwynZN    schedule 25.06.2020
comment
resizeToAvoidBottomInset: false на это не влияет. ValueListenableBuilder находится за пределами каркаса, потому что в предыдущей реализации мне нужно было использовать значение результата при построении каркаса. Но да, теперь его можно было переместить внутрь. - person Aaron; 25.06.2020
comment
Как насчет использования resizeToAvoidBottomInset и обертывания виджета SafeArea? - person EdwynZN; 25.06.2020
comment
resizeToAvoidBottomInset на это никак не влияет. SafeArea вокруг панели приложения: а) это выглядит странно, так как панель приложения должна немного находиться в небезопасной области, и б) и не влияет на поведение прокрутки вверх. - person Aaron; 25.06.2020
comment
Вы используете SliverSafeArea для SliverAppBar? или просто SafeArea над эшафотом? - person EdwynZN; 25.06.2020
comment
Это не имеет значения, потому что оба они неверны: и шаблон, и панель приложения должны находиться в небезопасной зоне. И это все еще не касается поведения прокрутки. - person Aaron; 26.06.2020