每次按下平面按钮时,有没有办法让我颤抖重建网格视图?
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 将重建屏幕。所以你可以做这样的事情。
我正在用 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 将重建屏幕。所以你可以做这样的事情。