Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
颤振:Listview在将项目添加到列表中后获取scrollcontroller的完整大小&;滚动到末尾_Listview_Flutter - Fatal编程技术网

颤振:Listview在将项目添加到列表中后获取scrollcontroller的完整大小&;滚动到末尾

颤振:Listview在将项目添加到列表中后获取scrollcontroller的完整大小&;滚动到末尾,listview,flutter,Listview,Flutter,post描述了一个非常类似的问题,但答案并不能解决所有问题: 我有一个很长的列表,用户可以在其中添加新项目(一次打开)。添加后/添加时,列表应滚动至其末尾 (顺便说一句,反向:true不是选项) 在阅读了另一篇文章之后,我理解了如何使用SchedulerBinding.instance.addPostFrameCallback((\u)=>scrollToEnd())应与技巧b/c一致,新列表maxScrollExtent将是正确的 但它不能可靠地工作: 当已经滚动到列表末尾或接近末尾时,一切正

post描述了一个非常类似的问题,但答案并不能解决所有问题:

我有一个很长的列表,用户可以在其中添加新项目(一次打开)。添加后/添加时,列表应滚动至其末尾

(顺便说一句,
反向: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);