How can fix ListView in column and add RefreshIndicator to the ListView

Viewed 5100

I have a ListView in column ,and need add RefreshIndicator to the ListView,but it not work well I tried contain the listView by Expanded,then list display well,but when call the RefreshIndicator ,app dump... some one can help me ,how to fix this code,thanks

import 'dart:async';

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    home: new MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  List<int> items = List.generate(16, (i) => i);

  Future<Null> _handleRefresh() async {
    await Future.delayed(Duration(seconds: 5), () {
      print('refresh');
      setState(() {
        items.clear();
        items = List.generate(40, (i) => i);
        return null;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Refresh"),
        ),
        body:  Column(
          children: <Widget>[RefreshIndicator(child:
            ListView.builder(
              itemCount: items.length,
            shrinkWrap: true,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text("Index$index"),
                );
              },
             ), onRefresh: _handleRefresh,)
          ],
        )

        );
  }
}
2 Answers

I have two remarks :

  1. You should use the Expanded widget with the flex param.
  2. You do not need to return anything in the setState method.
    import 'dart:async';
    import 'package:flutter/material.dart';
    void main() {
      runApp(new MaterialApp(
        home: new MyApp(),
      ));
    }

    class MyApp extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => MyAppState();
    }

    class MyAppState extends State<MyApp> {
      List<int> items = List.generate(16, (i) => i);

      Future<Null> _handleRefresh() async {
        await Future.delayed(Duration(seconds: 5), () {
          print('refresh');
          setState(() {
            items.clear();
            items = List.generate(40, (i) => i);
          });
        });
      }

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Refresh"),
          ),
          body: Column(
            children: <Widget>[
              Expanded(
                flex: 1,
                child: RefreshIndicator(
                  child: ListView.builder(
                    itemCount: items.length,
                    shrinkWrap: true,
                    itemBuilder: (context, index) {
                      return ListTile(
                        title: Text("Index$index"),
                      );
                    },
                  ),
                  onRefresh: _handleRefresh,
                ),
              )
            ],
          ),
        );
      }
    }

The answer above( by Tarek Baz) is correct, however in some special cases (like deep/complicated widget tree) it might not be enough and you might have to pass the physics parameter to the ListView.builder() function.

ListView.builder( 
physics: const AlwaysScrollableScrollPhysics(), 
itemCount: .... ... ) 
Related