每次按下平面按钮时,有没有办法让我颤抖重建网格视图?

Is there a way I can get flutter to rebuild a gridview every time a flatbutton is pressed?

我正在用 flutter 开发一个迷宫应用。我有一个由 100 个 flatButton 组成的网格,它们一开始都是灰色的。当按下 flatButton 时,我希望它在移动合法时变为绿色,在移动非法时变为红色(为此我使用了 splashColor 属性)。移动不断地从非法变为合法(基于用户当前所在的位置)并且所有按钮的 splashColor 应该动态更新。现在,只有按钮的 splashColor 才会在我单击它时发生变化。我希望整个 gridView 按钮在按下任何按钮时更新它们的 splashColor 属性。附上代码。非常感谢任何帮助!

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:flutter/scheduler.dart' show timeDilation;
//lastmove initially set to 1 for simplicity.
int lastMove=1;
class GameButton extends StatefulWidget {
  final int id;
  int onPath=0;

  bool testOnPath(){
    if (this.onPath==1){
      return true;
    }
  else {
    return false;
    }
  }

  bool testIfLegal(lastMove){
    return (((this.id-lastMove).abs()==1) ^ ((this.id-lastMove).abs()==10));
  }

  bool moveCheck(){
    if(this.testIfLegal(lastMove) & this.testOnPath()){
      return true;
    }
    else{
      return false;
    }
  }

  GameButton(this.id, lastMove);
  @override
  _GameButtonState createState() => _GameButtonState();

}

class _GameButtonState extends State<GameButton> {
  @override
  Widget build(BuildContext context) {
    return Container(
        decoration: BoxDecoration(border: Border.all(color: Colors.black)),
      child: FlatButton(
          color:Colors.grey,
          splashColor: widget.moveCheck()?Colors.green:Colors.red,
          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
          onPressed: () {
           bool a=widget.moveCheck();
           if(a){
             setState(() {
               lastMove=widget.id;
               print("GOOD MOVE");
             }
             );
           }
           else{
             print("Illegitmate Move");
           }
          },

          ),
    );
  }
}

class Maze extends StatefulWidget {
  List<GameButton> empty_grid = [for(var i=0; i<100; i++) new GameButton(i,lastMove)];
  @override
  _MazeState createState() => _MazeState();
}

class _MazeState extends State<Maze> {
  @override
  Widget build(BuildContext context) {
  }
}

void main() {
  //slow down animation to give user more time
  timeDilation = 3.0;
  Maze maze1 = new Maze();
  //filling maze manually-will be done with function in future
  (maze1.empty_grid[0]).onPath = 1;
  (maze1.empty_grid[10]).onPath = 1;
  (maze1.empty_grid[20]).onPath = 1;
  (maze1.empty_grid[30]).onPath = 1;
  (maze1.empty_grid[40]).onPath = 1;
  (maze1.empty_grid[50]).onPath = 1;
  (maze1.empty_grid[60]).onPath = 1;
  (maze1.empty_grid[70]).onPath = 1;
  (maze1.empty_grid[80]).onPath = 1;
  (maze1.empty_grid[90]).onPath = 1;
  (maze1.empty_grid[91]).onPath = 1;
  (maze1.empty_grid[92]).onPath = 1;
  (maze1.empty_grid[93]).onPath = 1;
  (maze1.empty_grid[94]).onPath = 1;
  (maze1.empty_grid[95]).onPath = 1;
  (maze1.empty_grid[96]).onPath = 1;
  (maze1.empty_grid[97]).onPath = 1;
  (maze1.empty_grid[98]).onPath = 1;
  (maze1.empty_grid[99]).onPath = 1;

//done filling maze1
    return runApp(
        MaterialApp(
              home: Scaffold(
                  backgroundColor: Colors.blue,
                  appBar: AppBar(
                    title: Text('Gorton Maze Test'),
                    backgroundColor: Colors.blueAccent,
                  ),
                  body: Center(
                        child: GridView.builder(
                          itemCount: 100,
                         gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 10, crossAxisSpacing: 0, mainAxisSpacing: 0),
                          shrinkWrap: true,
                          itemBuilder: (BuildContext context, int index){
                            return maze1.empty_grid[index];
                          },
                        )
                  ),
            ),
    )
    );
}

是的。如果你用 StreamController 包装,你可以更新整个 GridView。

另一方面,我不认为在 main class 中做所有事情是个好主意。您应该拆分 class 并更轻松地运行。它会让你的代码更干净。

    body: HomePage()),

而在主页中,我出于更多原因使用有状态小部件。

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  StreamController _controller;

  @override
  void initState() {
    super.initState();
    _controller = new StreamController();
  }

  @override
  void dispose() {
    _controller.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
        child: StreamBuilder(
            stream: _controller.stream,
            builder: (_, __) {
              return GridView.builder(
                itemCount: 100,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 10,
                    crossAxisSpacing: 0,
                    mainAxisSpacing: 0),
                shrinkWrap: true,
                itemBuilder: (BuildContext context, int index) {
                  return maze1.empty_grid[index];
                },
              );
            }));
  }
}

以及每次您想要更新网格视图时。您可以添加具有新值的 StreamController

_controller.add(null);

希望这个想法对您有所帮助。

对于您现有的设计,您可以通过在 GameButton 中定义一个回调来实现它,该回调指向 Maze class 中的一个方法。每次在更改按钮颜色后按下按钮时,您都会将回调调用到 Maze class 中,您也会在其中更改网格颜色。须藤代码:

class GameButton extends StatefulWidget {
    final VoidCallback clickCallback
    GameButton(this.id, lastMove, this.clickCallback);
    .....
}

class Maze extends StatefulWidget {
  List<GameButton> empty_grid = [for(var i=0; i<100; i++) new GameButton(i,lastMove, onButtonPressed)];
  @override
  _MazeState createState() => _MazeState();

  void onButtonPressed(){
     // change grid color based on index
  }
}

class _MazeState extends State<Maze> {
  @override
  Widget build(BuildContext context) {
  }
}

调用setstate方法即可。

在编写逻辑后单击按钮时使用 setstate 方法。基本上 setstate 将重建屏幕。所以你可以做这样的事情。