dart - 展开图块时如何滚动ExpansionTile / Listview?
问题描述
我们有一堆ExpansionTile
内一个ListView
(到目前为止还不算太疯狂,对吧?)。我们的用户希望我们在打开列表时“自动滚动”列表,ExpansionTile
这样新的展开图块现在位于屏幕的顶部(或尽可能位于顶部),这样他们就不必手动滚动查看我们刚刚打开的。
我认为我们需要类似on-- 并注册一个ScrollController
onExpansionChanged ListView
.. 来做一些事情。这对我来说有点模糊。:)
任何有关如何执行此操作的指示或帮助将不胜感激!
蒂亚!
解决方案
如果我得到了你的要求,基本上是一种自动ExpansionTile
向上滚动的方式,这样用户就不必手动查看它的内容,对吧?
然后,您实际上可以ScrollController
在您的中使用 aListView
并利用 的onExpansionChanged
回调ExpansionTile
根据磁贴的大小与其当前位置相应地向上/向下滚动它。
但现在你想知道:我怎么知道要滚动多少?
为此,您可以通过给它一些约束(例如构建一个或在这种特定情况下,您不确切知道高度将需要Container(heigh: 100.0))
多少像素。所以,ExpansionTile
我们可以使用 aGlobalKey
然后通过RenderBox
在运行时检查它来检查它的渲染高度,以确切知道它在折叠时占用了多少像素,并将它乘以它的索引。
ExpansionTile _buildExpansionTile(int index) {
final GlobalKey expansionTileKey = GlobalKey();
double previousOffset;
return ExpansionTile(
key: expansionTileKey,
onExpansionChanged: (isExpanded) {
if (isExpanded) previousOffset = _scrollController.offset;
_scrollToSelectedContent(isExpanded, previousOffset, index, expansionTileKey);
},
title: Text('My expansion tile $index'),
children: _buildExpansionTileChildren(),
);
}
好的,现在我们有了一个ListView
将 _buildExpansionTile
在其生成器中使用它的GlobalKey
. 我们还保存了ListView
展开图块时的滚动偏移量。但是,我们如何真正向上滚动以显示其内容?让我们看看_scrollToSelectedContent
方法。
void _scrollToSelectedContent(bool isExpanded, double previousOffset, int index, GlobalKey myKey) {
final keyContext = myKey.currentContext;
if (keyContext != null) {
// make sure that your widget is visible
final box = keyContext.findRenderObject() as RenderBox;
_scrollController.animateTo(isExpanded ? (box.size.height * index) : previousOffset,
duration: Duration(milliseconds: 500), curve: Curves.linear);
}
}
因此,我们通过其键访问渲染对象,然后使用ListView
滚动控制器在展开时向上滚动,在折叠时通过将其高度乘以其索引来向下滚动回其初始位置。您不必向后滚动,这只是我对这个示例的个人偏好。这将导致如下结果:
在这里你有一个完整的例子StatefulWidget
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: MyApp()));
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final ScrollController _scrollController = ScrollController();
void _scrollToSelectedContent(bool isExpanded, double previousOffset, int index, GlobalKey myKey) {
final keyContext = myKey.currentContext;
if (keyContext != null) {
// make sure that your widget is visible
final box = keyContext.findRenderObject() as RenderBox;
_scrollController.animateTo(isExpanded ? (box.size.height * index) : previousOffset,
duration: Duration(milliseconds: 500), curve: Curves.linear);
}
}
List<Widget> _buildExpansionTileChildren() => [
FlutterLogo(
size: 50.0,
),
Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse vulputate arcu interdum lacus pulvinar aliquam. Donec ut nunc eleifend, volutpat tellus vel, volutpat libero. Vestibulum et eros lorem. Nam ut lacus sagittis, varius risus faucibus, lobortis arcu. Nullam tempor vehicula nibh et ornare. Etiam interdum tellus ut metus faucibus semper. Aliquam quis ullamcorper urna, non semper purus. Mauris luctus quam enim, ut ornare magna vestibulum vel. Donec consectetur, quam a mattis tincidunt, augue nisi bibendum est, quis viverra risus odio ac ligula. Nullam vitae urna malesuada magna imperdiet faucibus non et nunc. Integer magna nisi, dictum a tempus in, bibendum quis nisi. Aliquam imperdiet metus id metus rutrum scelerisque. Morbi at nisi nec risus accumsan tempus. Curabitur non sem sit amet tellus eleifend tincidunt. Pellentesque sed lacus orci.',
textAlign: TextAlign.justify,
),
];
ExpansionTile _buildExpansionTile(int index) {
final GlobalKey expansionTileKey = GlobalKey();
double previousOffset;
return ExpansionTile(
key: expansionTileKey,
onExpansionChanged: (isExpanded) {
if (isExpanded) previousOffset = _scrollController.offset;
_scrollToSelectedContent(isExpanded, previousOffset, index, expansionTileKey);
},
title: Text('My expansion tile $index'),
children: _buildExpansionTileChildren(),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MyScrollView'),
),
body: ListView.builder(
controller: _scrollController,
itemCount: 100,
itemBuilder: (BuildContext context, int index) => _buildExpansionTile(index),
),
);
}
}
推荐阅读
- rxjs - 我可以做些什么来执行多个单曲,但只有在前一个完成后才移动到下一个?
- angular - 如何测试路由器订阅
- cakephp-3.0 - Cakephp 3 搜索插件或将关键字读入pdf文件的解决方案
- google-app-engine - 如何确保应用引擎应用仅对 Google Cloud Task 可用?
- python - 我想在 python 中实现三边测量。我找不到我的功能有什么问题?
- sql - 如何在 SAP HANA 数据库中的两个表之间进行单位转换
- html - 在较大的屏幕分辨率(如 2048 像素)的情况下,HTML 正文不会覆盖全屏
- testing - 使用另一个 TestRunner 时如何测试 Java DSL 中定义的 Camel 路由?
- rust - 向结构添加泛型参数后借用检查器错误
- android - 在哪里可以找到 Squid 使用的低延迟手写笔 API?