Flutter setState更改,但不重新呈现 [英] Flutter setState changing, but not rerendering

查看:984
本文介绍了Flutter setState更改,但不重新呈现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个简单的屏幕,其中包含字母列表并将其呈现在网格中。我有一个带随机播放方法的按钮,可以随机播放此列表。在我的构建方法中,我看到状态正在用新列表更新,并且每次按下按钮时都会打印出一个随机排列的列表,但是屏幕没有变化。

  class _LetterContainerState扩展了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
小部件构建(BuildContext上下文){
print(’LETTERS’);
print(_letters);
List< LetterTile> letterTiles =
_letters.map< LetterTile>((letter)=> new LetterTile(letter))。toList();

返回新列(
个孩子:< Widget> [
个新FlatButton(onPressed:shuffle,child:new Text( Shuffle))),
个new Container(

颜色:Colors.amberAccent,
约束条件:BoxConstraints.expand(高度:200.0),
子对象:新的GridView.count(
crossAxisCount:4,
mainAxisSpacing:4.0,
crossAxisSpacing:4.0,
儿童:letterTiles,
))
],
);
}
}

编辑:

  import'package:flutter / material.dart'; 

类元音{
静态const值= ['A','E','I','O','U'];

静态布尔值isVowel(字符串字母){
返回values.contains(letter.toUpperCase());
}
}

类LetterTile扩展了StatefulWidget {
最终字符串值;
的最终bool isVowel;

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

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

}

类_LetterTileState扩展了State< LetterTile> {
_LetterTileState(this.value);

最终字符串值;

@override
小部件build(BuildContext context){
颜色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,
样式:TextStyle(fontSize:40.0,color:Colors.white)


);

}

}


解决方案

如果将示例LetterTile小部件替换为文本小部件,则改组将再次起作用。这不起作用的原因是,仅在第一次实例化窗口小部件时才创建State对象。因此,通过将值直接传递给状态,可以确保它永远不会更新。而是通过 widget.value 引用值:

 类LetterTile扩展了StatefulWidget {
最终字串值;
的最终bool isVowel;

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

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

class _LetterTileState扩展State< LetterTile> {
@override
小部件build(BuildContext context){
颜色color = Vowels.isVowel(widget.value)吗? Colors.green:Colors.deepOrange;
return Card(
color:color,
child:Padding(
padding:EdgeInsets.all(8.0),
child:Text(
小部件。值,
样式:TextStyle(fontSize:40.0,color:Colors.white)


);
}
}



编辑:更多解释。



State对象的要点是它在构建之间是持久的。首次构建特定的LetterTile小部件时,这还将创建一个新的State对象。第二次调用,框架找到现有的State对象并重新使用它。这就是您如何将计时器,网络请求以及其他资源绑定到不可变的小部件树上的方法。对象,每个人都将与第一个通过的字母保持联系。相反,通过从小部件上读取它们,当与State对象关联的小部件被替换时,您始终会收到最新的数据。


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. 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. The reason this is not working is that a State object is only created the first time a widget is instantiated. So by passing the value directly to the state, you ensure that it never updates. Instead reference the value via 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. The first time you build a particular LetterTile widget, this also creates a new State object. The second time build is called, the framework finds the existing State object and reuses it. 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. 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.

这篇关于Flutter setState更改,但不重新呈现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆