调用setState()时Flutter ListView不会更改

时间:2019-10-04 06:53:04

标签: flutter dart

我是使用Flutter / Dart的新手,我很难理解为什么_updateResults()调用setState()时,以下代码为什么不更新ListView内容。我什至添加了一条打印语句来显示_results的内容,并且可以看到项目已添加到列表中,但显示从未更新。

class SearchHomePage extends StatefulWidget {
  SearchHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  createState() => _SearchHomePageState();
}

class _SearchHomePageState extends State<SearchHomePage> {
  List<Widget> _results = <Widget>[];

  @override
  void initState() {
    super.initState();
    _results.add(Text("testing"));
  }

  void _updateResults(String text) {
    setState(() {
      _results.add(Text(text));
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(children: [
        Container(
          child: TextField(
            onSubmitted: (String text) {
              _updateResults(text);
            },
          ),
        ),
        Expanded(
          child: ListView(children: _results)
        ),
      ]),
    );
  }
}

如果我将ListView部分更改为:

Expanded(
   child: ListView(children: _results.toList())
)

然后它将起作用,我不确定为什么,因为它已经是列表。到底发生了什么,为什么它不能仅与ListView一起使用?

3 个答案:

答案 0 :(得分:0)

它不起作用,因为您是将新项目添加到现有列表中,而不是创建新列表。

这将解决您的问题:


class SearchHomePage extends StatefulWidget {
  SearchHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  createState() => _SearchHomePageState();
}

class _SearchHomePageState extends State<SearchHomePage> {
  List<Widget> _results = <Widget>[];

  @override
  void initState() {
    super.initState();
    _results.add(Text("testing"));
  }

  void _updateResults(String text) {
    setState(() {
      _results = [..._results, Text(text)];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(children: [
        Container(
          child: TextField(
            onSubmitted: (String text) {
              _updateResults(text);
            },
          ),
        ),
        Expanded(
            child: ListView(children: _results)
        ),
      ]),
    );
  }
}

注意:最好做以下事情,而不是创建小部件并将它们保存在数组中:


class SearchHomePage extends StatefulWidget {
  SearchHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  createState() => _SearchHomePageState();
}

class _SearchHomePageState extends State<SearchHomePage> {
  List<String> _results = <String>[];

  @override
  void initState() {
    super.initState();
    _results.add("testing");
  }

  void _updateResults(String text) {
    setState(() {
      _results = [..._results, text];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(children: [
        Container(
          child: TextField(
            onSubmitted: (String text) {
              _updateResults(text);
            },
          ),
        ),
        Expanded(
            child: ListView(
          children: _results.map((v) => Text(v)).toList(),
        )),
      ]),
    );
  }
}

调用.toList()时,它将创建一个新的列表实例(旧列表的副本)

答案 1 :(得分:0)

      ListView(
        shrinkWrap: true,
        children: _results.map((one) => one).toList(),
      ),

      ListView.builder(

        shrinkWrap: true,
        itemCount: _results.length,
        itemBuilder: (context, index) => _results[index],
      ),

如果您努力根据自己的要求获得输出,则必须像上面对以下代码的理解那样更改代码:

Expanded(
   child: ListView(children: _results.toList()))

请同时放置两个列表中的任何一个...

答案 2 :(得分:0)

来自StatefulWidget documentation

  

StatefulWidget实例本身是不可变的,并将其可变状态存储在由createState方法创建的单独的State对象中,或存储在该State所预订的对象中。[...]

摘自this文章:

  

从定义上说,不可变是指一旦创建,就不能更改对象/变量。因此,不必更改对象的属性,而必须复制(或克隆)整个对象,然后在此过程中更改相关属性。

您使用相同的数组创建了ListView。您更改了数组的内容,但没有更改对该对象的引用。 这就是为什么当您使用_results.toList()时它起作用的原因,因为.toList()“创建了一个包含此[Iterable]元素的[List]”。

另一个解决方案可能是:

setState(() {
  _results = List.from(_results)
    ..add(Text(text));
});