如何更新内置在FutureBuilder中的小部件状态

时间:2020-07-27 02:09:02

标签: flutter flutter-widget flutter-futurebuilder

之前,我使用ListBuilder生成了70个数字的列表,并且可以正常工作,但是花了很长时间才能将70个数字生成到自定义小部件中,并且当我点击一个数字只是为了更改背景颜色状态时,状态更改花费了几毫秒的时间。

ow

现在,我正在使用FutureBuilder以便能够在等待生成的70个整数的同时加载屏幕。但是,当我点击球的编号时,背景颜色不会更新……就像setState()在Future ListBuilder中不起作用。

这个问题:“ Flutter - How to update state (or value?) of a Future/List used to build ListView (via FutureBuilder) ”非常相似,但是并不能解决我的问题。

这是构建方法中的代码

Flexible(
                child:FutureBuilder<List<Widget>>(
                  future: ballNumbers,
                  builder: (context, snapshot){
                    if(snapshot.connectionState != ConnectionState.done){
                      return Center(child: CircularProgressIndicator());
                    }
                    if(snapshot.hasError){
                      return Center(child: Text("An error has occured"));
                    }
                    List<Widget> balls = snapshot.data ?? [];
                    return GridView.count(
                      crossAxisCount: 9,
                      children: balls,
                    );
                  }
                )

这是我启动功能状态的方法:

Future<List<Widget>> ballNumbers;
List<int> picks = []; 

@override
void initState() {
    ballNumbers = getBallNumbers();
});

  Future<List<Widget>> getBallNumbers() async {
    return List.generate(limitBallNumber,(number){
      number = number + 1;
      return Padding(
        padding:EdgeInsets.all(2.5),
        child:Ball(
          number : number,
          size: ballWidth,
          textColor:(picks.contains(number)) ? Colors.black : Colors.white,
          ballColor: (picks.contains(number)) ? Style.selectedBallColor : Style.ballColor,
          onTap:(){
            setState((){
                picks.contains(number) ? picks.remove(number) : picks.add(number);
            });
          }
        )
      );
    });
  }

已更新:这是Ball小部件的类

class Ball extends StatelessWidget {
  final Color ballColor;
  final Color textColor;
  final double size;
  final double fontSize;
  final int number;
  final VoidCallback onTap;

  Ball({Key key, @required this.number, 
    this.textColor, 
    this.ballColor,
    this.onTap,
    this.size = 55.0,
    this.fontSize = 14,
  }) : super(key : key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: size,
      width: size,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        gradient: LinearGradient(
          colors: [
            Style.secondaryColor,
            ballColor != null ? ballColor : Style.ballColor,
          ],
          begin: Alignment.bottomLeft,
          end: Alignment.topRight
        )
      ),
      child: FlatButton(
        padding: EdgeInsets.all(0),
        child: Container(
          child: Text(
            number.toString().length > 1 ? number.toString() : "0" + number.toString(),
            style: TextStyle(
              fontSize: fontSize,
              color: textColor != null ? textColor : Colors.white
            ),
          ),
          padding: const EdgeInsets.all(4.0),
          decoration:BoxDecoration(
            color: Colors.transparent,
            border: Border.all(color: textColor != null ? textColor : Colors.white,  width: 1),
            borderRadius: BorderRadius.circular(32),
          )
        ),
        color: Colors.transparent,
        onPressed: onTap,
      ),
    );
  }
}

1 个答案:

答案 0 :(得分:1)

问题在于getBallNumbers仅在initState中被调用一次,因此更新picks时没有关系,因为不会再次调用getBallNumbers更新传递给Ball小部件的颜色。

一个简单的解决方法是用getBallNumbers来调用build中的future: getBallNumbers(),但这会导致CircularProgressIndicator在每次点击时都显示为{{1 }}重新生成。

但是,理想情况下,您应该处理每个List的状态内的所有颜色变化,以免每次单击都被迫重建Ball。并且要在父窗口小部件的List中保持选定数字的List,您应该向每个球传递一个回调,以从父State中添加或删除其编号。


粗略的示例:

Ball类(修改为有状态并删除了不必要的参数;活动状态现在存储在球中,而不是仅存储在父级中):

List

父类(唯一需要修改的部分是class Ball extends StatefulWidget { final double size; final double fontSize; final int number; final VoidCallback toggleBall; final bool initialActiveState; Ball({Key key, @required this.number, this.toggleBall, this.size = 55.0, this.fontSize = 14, this.initialActiveState, }) : super(key : key); _BallState createState() => _BallState(); } class _BallState extends State<Ball> { bool isActive; @override void initState() { super.initState(); isActive = widget.initialActiveState; } @override Widget build(BuildContext context) { return Container( height: widget.size, width: widget.size, decoration: BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [ Style.secondaryColor, isActive ? Style.selectedBallColor : Style.ballColor, ], begin: Alignment.bottomLeft, end: Alignment.topRight ) ), child: FlatButton( padding: EdgeInsets.all(0), child: Container( child: Text( widget.number.toString().length > 1 ? widget.number.toString() : "0" + widget.number.toString(), style: TextStyle( fontSize: widget.fontSize, color: isActive ? Colors.black : Colors.white, ), ), padding: const EdgeInsets.all(4.0), decoration:BoxDecoration( color: Colors.transparent, border: Border.all(color: isActive ? Colors.black : Colors.white, width: 1), borderRadius: BorderRadius.circular(32), ) ), color: Colors.transparent, onPressed: () { if(!isActive && widget.activeBallList.length >= 7) { return; } setState(() { isActive = !isActive; }); widget.activeBallList.contains(widget.number) ? widget.activeBallList.remove(widget.number) : widget.activeBallList.add(widget.number); }, ), ); } } 的参数):

Ball