简体   繁体   English

Flutter setState改变,但不重新渲染

[英]Flutter setState changing, but not rerendering

I've created a simple screen that takes a List of letters and renders them in a grid. 我创建了一个简单的屏幕,它接受一个字母列表并将它们呈现在网格中。 I have a button with a shuffle method that shuffles this list. 我有一个带有shuffle方法的按钮,可以随机播放此列表。 Inside my build method, I see that the state is getting updated with the new list and is printing out a shuffled list each time the button is pressed, but the screen doesn't change. 在我的构建方法中,我看到状态正在使用新列表进行更新,并且每次按下按钮时都会打印出一个洗牌列表,但屏幕不会更改。

class _LetterContainerState extends State<LetterContainer> {
  List<String> _letters = ['D', 'A', 'B', 'C', 'E', 'F', 'G', 'H'];



  void shuffle() {
    var random = new Random();
    List<String> newLetters = _letters;
    for (var i = newLetters.length - 1; i > 0; i--) {
      var n = random.nextInt(i + 1);
      var temp = newLetters[i];
      newLetters[i] = newLetters[n];
      newLetters[n] = temp;
    }

    setState(() {
      _letters = newLetters;
    });
  }

  @override
  Widget build(BuildContext context)  {
    print('LETTERS');
    print(_letters);
    List<LetterTile> letterTiles =
        _letters.map<LetterTile>((letter) => new LetterTile(letter)).toList();

    return new Column(
      children: <Widget>[
        new FlatButton(onPressed: shuffle, child: new Text("Shuffle")),
        new Container(

            color: Colors.amberAccent,
            constraints: BoxConstraints.expand(height: 200.0),
            child: new GridView.count(
              crossAxisCount: 4,
              mainAxisSpacing: 4.0,
              crossAxisSpacing: 4.0,
              children: letterTiles,
            ))
      ],
    );
  }
}

EDIT: 编辑:

import 'package:flutter/material.dart';

class Vowels {
  static const values = ['A', 'E', 'I', 'O', 'U'];

  static bool isVowel(String letter) {
    return values.contains(letter.toUpperCase());
  }
}

class LetterTile extends StatefulWidget {
  final String value;
  final bool isVowel;

  LetterTile(value)
            : value = value,
              isVowel = Vowels.isVowel(value);

  @override
  _LetterTileState createState() => new _LetterTileState(this.value);

}

class _LetterTileState extends State<LetterTile> {
  _LetterTileState(this.value);

  final String value;

  @override
  Widget build(BuildContext context) {
    Color color = Vowels.isVowel(this.value) ? Colors.green : Colors.deepOrange;
    return new
    Card(
      color: color,
      child: Padding(
        padding: EdgeInsets.all(8.0),
        child: Text(
          this.value,
          style: TextStyle(fontSize: 40.0, color: Colors.white)
        )
      )
    );

  }

}

If you replace your example LetterTile widget with a Text widget, the shuffling will work again. 如果您使用文本小部件替换示例LetterTile小部件,则重排将再次起作用。 The reason this is not working is that a State object is only created the first time a widget is instantiated. 这不起作用的原因是State对象仅在第一次实例化窗口小部件时创建。 So by passing the value directly to the state, you ensure that it never updates. 因此,通过将值直接传递给状态,可以确保它永远不会更新。 Instead reference the value via widget.value : 而是通过widget.value引用该值:

class LetterTile extends StatefulWidget {
  final String value;
  final bool isVowel;

  LetterTile(this.value) : isVowel = Vowels.isVowel(value);

  @override
  _LetterTileState createState() => new _LetterTileState();
}

class _LetterTileState extends State<LetterTile> { 
  @override
  Widget build(BuildContext context) {
    Color color = Vowels.isVowel(widget.value) ? Colors.green : Colors.deepOrange;
    return Card(
      color: color,
      child: Padding(
        padding: EdgeInsets.all(8.0),
        child: Text(
          widget.value,
          style: TextStyle(fontSize: 40.0, color: Colors.white)
        )
      )
    );
  }
}

Edit: Some more explanation. 编辑:更多解释。

The point of a State object is that it is persistent across builds. State对象的意思是它在构建过程中是持久的。 The first time you build a particular LetterTile widget, this also creates a new State object. 第一次构建特定的LetterTile小部件时,这也会创建一个新的State对象。 The second time build is called, the framework finds the existing State object and reuses it. 第二次调用构建时,框架会查找现有的State对象并重用它。 This is how you can have resources like timers, network requests, and other bound to an immutable tree of widgets. 这就是如何将定时器,网络请求等资源绑定到不可变的小部件树的方法。

In your case, since you passed the letter to the State object, each one would stay associated with whatever the first passed letter was. 在您的情况下,由于您将该字母传递给State对象,因此每个字母都会与第一个传递的字母保持关联。 Instead, by reading them off the widget you always receive the most up to date data when the widget associated with the State object is replaced. 相反,通过从小部件中读取它们,当替换与State对象关联的小部件时,您始终会收到最新的数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM