颤振:Listview在将项目添加到列表中后获取scrollcontroller的完整大小&;滚动到末尾
post描述了一个非常类似的问题,但答案并不能解决所有问题: 我有一个很长的列表,用户可以在其中添加新项目(一次打开)。添加后/添加时,列表应滚动至其末尾 (顺便说一句,颤振:Listview在将项目添加到列表中后获取scrollcontroller的完整大小&;滚动到末尾,listview,flutter,Listview,Flutter,post描述了一个非常类似的问题,但答案并不能解决所有问题: 我有一个很长的列表,用户可以在其中添加新项目(一次打开)。添加后/添加时,列表应滚动至其末尾 (顺便说一句,反向:true不是选项) 在阅读了另一篇文章之后,我理解了如何使用SchedulerBinding.instance.addPostFrameCallback((\u)=>scrollToEnd())应与技巧b/c一致,新列表maxScrollExtent将是正确的 但它不能可靠地工作: 当已经滚动到列表末尾或接近末尾时,一切正
反向:true
不是选项)
在阅读了另一篇文章之后,我理解了如何使用SchedulerBinding.instance.addPostFrameCallback((\u)=>scrollToEnd())代码>应与技巧b/c一致,新列表maxScrollExtent
将是正确的
但它不能可靠地工作:
当已经滚动到列表末尾或接近末尾时,一切正常。
但是,当添加新项目时,列表滚动到其开始位置(或从末尾开始的某个位置),列表会滚动,但滚动位置正好被一个项目(最新的项目)关闭
我认为这可能与ListView.builder
不能让所有的孩子都活着有关,但如何解决呢
哦,还有一个额外的问题:刚刚发现了另一个非常奇怪的行为:在添加了两个项目之后,最后一个项目有点看不见了,但是列表不能滚动——这很奇怪。但更奇怪的是,在下一个添加项上,单击列表会滚动这一小段,但从未创建新项
这里有一个完整的例子:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() {
runApp(MyList());
}
class MyList extends StatefulWidget {
MyList({Key key}) : super(key: key);
@override
_MyListState createState() => _MyListState();
}
var items = List<String>.generate(8, (i) => "Item $i");
class _MyListState extends State<MyList> {
static ScrollController _scrollController = ScrollController();
void add() {
setState(() {
items.add("new Item ${items.length}");
print(items.length);
});
SchedulerBinding.instance.addPostFrameCallback((_) => scrollToEnd());
}
void scrollToEnd() {
_scrollController.animateTo(_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 350), curve: Curves.easeOut);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "List",
home: Scaffold(
appBar: AppBar(
title: Text("List"),
),
body: ListView.builder(
controller: _scrollController,
itemCount: items.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index]}'),
);
},
),
bottomSheet: Container(
decoration: BoxDecoration(
border:
Border(top: BorderSide(color: Colors.black, width: 1))),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () {
add();
},
child: Icon(Icons.add),
)
],
))),
);
}
}
导入“包:flift/foundation.dart”;
进口“包装:颤振/材料.省道”;
导入“package:flatter/scheduler.dart”;
void main(){
runApp(MyList());
}
类MyList扩展了StatefulWidget{
MyList({Key}):super(Key:Key);
@凌驾
_MyListState createState();
}
var items=List.generate(8,(i)=>“Item$i”);
类_MyListState扩展状态{
静态ScrollController_ScrollController=ScrollController();
void add(){
设置状态(){
items.add(“newitem${items.length}”);
打印(项目长度);
});
SchedulerBinding.instance.addPostFrameCallback(()=>scrollToEnd());
}
void scrollToEnd(){
_scrollController.animateTo(_scrollController.position.maxScrollExtent,
持续时间:常数持续时间(毫秒:350),曲线:Curves.easeOut);
}
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“名单”,
家:脚手架(
appBar:appBar(
标题:文本(“列表”),
),
正文:ListView.builder(
控制器:\ u滚动控制器,
itemCount:items.length,
收缩膜:对,
itemBuilder:(上下文,索引){
返回列表块(
标题:文本(“${items[index]}”),
);
},
),
底板:集装箱(
装饰:盒子装饰(
边界:
边框(顶部:边框侧边(颜色:Colors.black,宽度:1)),
孩子:排(
mainAxisAlignment:mainAxisAlignment.end,
儿童:[
浮动操作按钮(
已按下:(){
添加();
},
子:图标(Icons.add),
)
],
))),
);
}
}
我将滚动到maxScrollExtent
与可滚动组合在一起。确保可修改
,并修复了彼此的缺陷
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class MyList extends StatefulWidget {
MyList({Key key}) : super(key: key);
@override
_MyListState createState() => _MyListState();
}
class _MyListState extends State<MyList> {
final ScrollController _scrollController = ScrollController();
final lastKey = GlobalKey();
List<String> items;
@override
void initState() {
super.initState();
items = List<String>.generate(8, (i) => "Item $i");
}
void add() {
setState(() {
items.add("new Item ${items.length}");
});
SchedulerBinding.instance.addPostFrameCallback((_) => scrollToEnd());
}
void scrollToEnd() async {
await _scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 350),
curve: Curves.easeOut);
Scrollable.ensureVisible(lastKey.currentContext);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "List",
home: Scaffold(
body: ListView.builder(
controller: _scrollController,
itemCount: items.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index]}'),
key: index == items.length - 1 ? lastKey : null,
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
add();
},
child: Icon(Icons.add),
),
));
}
}
导入“包装:颤振/材料.省道”;
导入“package:flatter/scheduler.dart”;
类MyList扩展了StatefulWidget{
MyList({Key}):super(Key:Key);
@凌驾
_MyListState createState();
}
类_MyListState扩展状态{
最终ScrollController_ScrollController=ScrollController();
final lastKey=GlobalKey();
清单项目;
@凌驾
void initState(){
super.initState();
项目=列表。生成(8,(i)=>“项目$i”);
}
void add(){
设置状态(){
items.add(“newitem${items.length}”);
});
SchedulerBinding.instance.addPostFrameCallback(()=>scrollToEnd());
}
void scrollToEnd()异步{
等待\u scrollController.animateTo(
_scrollController.position.maxScrollExtent,
持续时间:常数持续时间(毫秒:350),
曲线:Curves.easeOut);
可滚动。可修改(lastKey.currentContext);
}
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“名单”,
家:脚手架(
正文:ListView.builder(
控制器:\ u滚动控制器,
itemCount:items.length,
收缩膜:对,
itemBuilder:(上下文,索引){
返回列表块(
标题:文本(“${items[index]}”),
key:index==items.length-1?lastKey:null,
);
},
),
浮动操作按钮:浮动操作按钮(
已按下:(){
添加();
},
子:图标(Icons.add),
),
));
}
}
可滚动。EnsureRevible
如果项目尚未创建,则自身无法提供可见性,但当项目非常接近时,会处理这些可见性。指定过大的滚动位置不会出错,然后ScrollController会自动滚动到最终最大值。我定义一个scrollController并执行以下命令:
_scrollController.animateTo(
_scrollController.position.maxScrollExtent + 200,
duration: const Duration(milliseconds: 350),
curve: Curves.easeOut);
或
太棒了,谢谢你!这很有效。但这仍然感觉像是一个解决办法。你有什么解释为什么这个双重功能是必要的吗?或者知道那个奇怪的缺失列表项吗?是的,这是一个解决办法。我相信maxScrollExtent计算的错误是由动态创建的元素和新元素之间的冲突引起的。谢谢。我会找时间在flifter上提交一份bug报告。只要没有人提出(甚至)更好的答案/解决方案,这个答案就是公认的答案。谢谢你,伙计!
_scrollController.jumpTo(_scrollController.position.maxScrollExtent + 200);