【问题标题】:Infinite Scroll listview - setState() or markNeedsBuild called during build无限滚动列表视图 - 在构建期间调用 setState() 或 markNeedsBuild
【发布时间】:2018-07-09 16:12:29
【问题描述】:

我正在创建一个无限滚动 listView,我想在 _loadNames 函数中使用 setState 将 _loadingState 字符串从“正在加载...”更改为“已加载”,但是当从 itemBuilder 调用 _loadNames 时,我得到“在构建错误期间调用 setState”。使用 RefreshIndicator 可以正常工作并更新项目,但滚动到底部会导致错误。我如何能够从 ListViews 构建器调用 _loadNames 而不会出现错误或我可以使用什么其他方法。 注意:不想使用 redux 或 bloc。

class _HomePageState extends State<HomePage> {
     List<String> names = [];
     List<String> _shownNames = [];
     int currentPage = 0;
     int limit = 20;
     String _loadingState = 'loading';
     bool loading = true;

     @override
     void initState() {
       super.initState();
       for (int i = 0; i < 200; i++) {
         names.add("hello $i");
       }
       _loadNames();
     }

     @override
     Widget build(BuildContext context) {
       // TODO: implement build
       return new Scaffold(
         appBar: new AppBar(title: new Text('User')),
         body: Column(children: <Widget>[
           Text(_loadingState),
           Expanded(child:_getListViewWidget()),
         ],)
       );
     }

     Widget _getListViewWidget(){
       ListView lv =  new ListView.builder(
         itemCount: _shownNames.length,
         itemBuilder: (context, index){
         if(index >= _shownNames.length - 5 && !loading){
           _loadNames(); // Getting error when this is called
         }
         return  ListTile(
           title: Text(_shownNames[index]),
         );
       });

       RefreshIndicator refreshIndicator = new RefreshIndicator(
         key: _refreshIndicatorKey,
         onRefresh: (){
           _loadNames();
           return null;
         },
         child: lv
       );
       return refreshIndicator;
     }

    _loadNames(){
       loading = true;
       setState(() {
         _loadingState = 'loading...';
       });

       new Timer(const Duration(seconds: 5), () {
          setState(() {
            _shownNames.addAll(names.getRange(currentPage, currentPage + limit));
           currentPage += limit;
           _loadingState = 'loaded';
         });
         loading = false;
       });
     }
  }

【问题讨论】:

    标签: android ios dart flutter


    【解决方案1】:

    更改_loadNames() {

    到

    _loadNames(){
       loading = true;
       // setState(() {
         _loadingState = 'loading...';
       // });
    

    和

         onRefresh: (){
           _loadNames();
           return null;
         },
    

    到

         onRefresh: (){
           setState(() => _loadNames());
         },
    

    更新

    _loadNames(){
       loading = true;
    
       new Future.delayed(Duration.zero, () => setState(() {
         _loadingState = 'loading...';
       }));
    

    【讨论】:

    • 非常感谢您的帮助。主要问题来自 ListViews itemBuilder。当在 itemBuilder 中调用 loadNames() 而不在 loadNames 函数中使用 setState 时,如何显示“正在加载...”或“已加载”文本?我想要实现的只是一个带有进度指示器的无限滚动列表视图。
    • 我更新了我的答案。如果你延迟了setState(),它不会干扰build。这样您就可以保持其他代码不变。
    • @GünterZöchbauer 这种做事方式有名字吗?例如。我们是否直接设置静态字段而不使用 setState() 以免触发重建?
    • @Colin 我真的不理解你的评论。我的回答是不要从build() 打电话给setState()
    • 对不起,我不太清楚。在 OP 的问题中,在我看来,在 _loadNames() 中调用 setState() 会导致他的问题。在您的回复中,看起来您不是直接调用setState(),而是直接调用_loadingState = 'loading...';——对吗?
    猜你喜欢
    • 2018-05-15
    • 2021-06-11
    • 2020-10-05
    • 2020-12-12
    • 2020-12-28
    • 2021-01-06
    • 2021-06-06
    • 2021-05-31
    相关资源
    最近更新 更多