我们在ListView
中有一堆ExpansionTile
(到目前为止还不算太疯狂,对吧?我们的用户希望我们在打开ExpansionTile
时“自动滚动”列表,这样新扩展的磁贴就位于屏幕的顶部(或尽可能位于顶部),这样他们就不必手动滚动来查看我们刚刚打开的内容。
我认为我们需要在ListView
上使用类似ScrollController
的东西--并注册onExpansionChanged..做……做……某事。对我来说这是一件非常模糊的事情。:)
任何关于如何做到这一点的提示或帮助将不胜感激!
TIA!TIA!
3条答案
按热度按时间sqxo8psd1#
如果我得到了正确的你的要求,基本上是一种自动滚动你的
ExpansionTile
的方式,这样用户就不必手动查看它的内容,对吗?然后,您可以在
ListView
中实际使用ScrollController
,并利用ExpansionTile
的onExpansionChanged
回调来根据磁贴与目前的位置。但现在你想知道:* 我怎么知道要滚动多少?***
为此,要么你事先知道你的小部件的高度是多少,在构造它时给它一些约束(比如构建一个
Container(heigh: 100.0))
,或者,在这个特定的场景中,你不知道ExpansionTile
的高度到底需要多少像素。因此,我们可以使用GlobalKey
,然后通过在运行时检查其RenderBox
来检查其渲染高度,以准确地知道折叠时它占用了多少像素,并将其乘以其索引。好了,现在我们有一个
ListView
,它将在它的生成器中使用这个_buildExpansionTile
和一个GlobalKey
。当我们展开图块时,我们还保存了ListView
的滚动偏移。但是,我们实际上如何向上滚动以显示其内容?让我们看看_scrollToSelectedContent
方法。因此,我们通过其键访问渲染对象,然后使用
ListView
滚动控制器在展开时向上滚动,在折叠时通过将其高度乘以其索引向下滚动回到其初始位置。你不必向后滚动,这只是我个人对这个例子的偏好。这将导致如下结果:这里有一个完整的
StatefulWidget
示例,wqnecbli2#
如果你仍然面临这个问题,我发现了另一个解决方案,使用滚动部件。使用GlobalKey,我们必须将ExpansionTile的当前上下文传递给Scrollable类的ensureVisible方法,它将完成所有工作。
为了获得更高的可重用性,请在GlobalKey上创建扩展:
然后在Widget中声明一个全局键:
并将此全局密钥分配给扩展块。另外,当平铺展开时,调用我们上面定义的ensureVisible()方法。
你可以查看我的文章How to scroll an ExpansionTile when it is expanded?了解更多信息。
kse8i1jr3#
根据这个答案,你可以通过从ListView的控制器中获取ListView的当前滚动偏移量来计算需要滚动多少:
并将其添加到当前ExpansionTile Y位置,该位置由其键给出:
此位置考虑状态栏和AppBar的高度,因此滚动点可以通过以下方式计算:
MediaQueryData.fromWindow(window).padding.top
将给予状态栏的高度,从constats.dart中可以得到AppBar的高度:您可以通过检查scrollPoint是否低于滚动的最大范围来避免最后一项的错误计算:
注意ExpansionTiles自己的扩展动画需要200毫秒,如其定义所示:
const Duration _kExpand = Duration(milliseconds: 200);
因此,最好在开始滚动之前等待扩展动画完成,以便获得更新的值。一种方法是使用
Future.delayed(duration)
延迟调用:除此之外,你可以制作你自己的ExpansionTile,并给予你想要的任何扩展时间。