如何抑制 Flutter 中的滚动到视图行为?
How to suppress scroll-into-view behavior in Flutter?
我有一个 CustomScrollView
和一个隐藏在滚动条上的 SliverAppBar
。
应用栏上有一个搜索按钮,按下后会在应用栏中添加一个 TextField
。
当字段获得焦点时,它会导致滚动视图一直滚动到顶部,并且应用栏卡在“不安全”区域:
Scaffold docs 提到当显示键盘时脚手架的插图会发生变化并重建脚手架,导致“如果焦点小部件在可滚动容器内,它将滚动到视图中”。
这似乎是我不想要的行为。我看了但无法理解该机制或如何抑制它。这样做可以吗?
图中视图的源代码是here。
我还注意到,在我之前使用非条形标准小部件的实现中没有发生此问题。我怀疑这是因为应用栏不在可滚动视图中,而 SliverAppBar
在 CustomScrollView
内部,以便它可以与主体交互。
就像文档提到的那样,尝试在脚手架小部件中将 resizeToAvoidBottomInset 参数设置为 false(默认为 true)https://api.flutter.dev/flutter/material/Scaffold/resizeToAvoidBottomInset.html
另外,我建议在脚手架之后创建 ValueListenableBuilder(作为正文中的第一个小部件)以避免重建整个脚手架而只重建正文小部件
编辑:此问题已由 this PR 修复,该问题似乎首先出现在 Flutter 1.22.0 中。
我花了一些时间进行调查,但我最终找到了这种行为的机制。
TextField
换行 EditableText
。当后者获得焦点时,它将调用 _showCaretOnScreen
, which includes a call to renderEditable.showOnScreen
。这会冒泡并最终导致滚动行为。
如果我们向 TextField
提供一个总是 return 的黑客 ScrollController
,我们可以强制 _showCaretOnScreen
提前 here return 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;
}
该行为似乎不是故意的,因此我将其报告为 bug #60422。
注意事项
此解决方法可能不是很稳定。
我不知道 hasClients
覆盖可能会产生什么不利影响。
docs for TextField
说 scrollController
用于“垂直滚动输入”。在此用例中,我们无论如何都不希望垂直滚动,因此解决方法可能不会导致任何问题。在我的简短测试中,它似乎没有引起水平(溢出)滚动的问题。
我有一个 CustomScrollView
和一个隐藏在滚动条上的 SliverAppBar
。
应用栏上有一个搜索按钮,按下后会在应用栏中添加一个 TextField
。
当字段获得焦点时,它会导致滚动视图一直滚动到顶部,并且应用栏卡在“不安全”区域:
Scaffold docs 提到当显示键盘时脚手架的插图会发生变化并重建脚手架,导致“如果焦点小部件在可滚动容器内,它将滚动到视图中”。
这似乎是我不想要的行为。我看了但无法理解该机制或如何抑制它。这样做可以吗?
图中视图的源代码是here。
我还注意到,在我之前使用非条形标准小部件的实现中没有发生此问题。我怀疑这是因为应用栏不在可滚动视图中,而 SliverAppBar
在 CustomScrollView
内部,以便它可以与主体交互。
就像文档提到的那样,尝试在脚手架小部件中将 resizeToAvoidBottomInset 参数设置为 false(默认为 true)https://api.flutter.dev/flutter/material/Scaffold/resizeToAvoidBottomInset.html
另外,我建议在脚手架之后创建 ValueListenableBuilder(作为正文中的第一个小部件)以避免重建整个脚手架而只重建正文小部件
编辑:此问题已由 this PR 修复,该问题似乎首先出现在 Flutter 1.22.0 中。
我花了一些时间进行调查,但我最终找到了这种行为的机制。
TextField
换行 EditableText
。当后者获得焦点时,它将调用 _showCaretOnScreen
, which includes a call to renderEditable.showOnScreen
。这会冒泡并最终导致滚动行为。
如果我们向 TextField
提供一个总是 return 的黑客 ScrollController
,我们可以强制 _showCaretOnScreen
提前 here return 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;
}
该行为似乎不是故意的,因此我将其报告为 bug #60422。
注意事项
此解决方法可能不是很稳定。
我不知道 hasClients
覆盖可能会产生什么不利影响。
docs for TextField
说 scrollController
用于“垂直滚动输入”。在此用例中,我们无论如何都不希望垂直滚动,因此解决方法可能不会导致任何问题。在我的简短测试中,它似乎没有引起水平(溢出)滚动的问题。