I am trying to create a custom Housie Game Ticket Generator in Flutter, in which I have to randomly select a button from a 4X3 table of buttons, and show a no. on that button. On clicking the button, it changes it's colour from Green to Red.
I have created a 4X3 table of buttons by hard coding all the cells as seen below. Now I want to select some random buttons from the table and set an onPressed function on them. How can I proceed?
body: new Container(
child: new Table(
border: TableBorder.all(),
children: [
TableRow(
children: [
new FlatButton(
color: Colors.white,
onPressed: () {},
),
new FlatButton(
color: Colors.white,
onPressed: () {},
),
new FlatButton(
color: Colors.white,
onPressed: () {},
),
new FlatButton(
color: Colors.white,
onPressed: () {},
)
]
),
TableRow(
children: [
new FlatButton(
color: Colors.white,
onPressed: () {},
),
new FlatButton(
color: Colors.white,
onPressed: () {},
),
new FlatButton(
color: Colors.white,
onPressed: () {},
),
new FlatButton(
color: Colors.white,
onPressed: () {},
)
]
),
TableRow(
children: [
new FlatButton(
color: Colors.white,
onPressed: () {},
),
new FlatButton(
color: Colors.white,
onPressed: () {},
),
new FlatButton(
color: Colors.white,
onPressed: () {},
),
new FlatButton(
color: Colors.white,
onPressed: () {},
)
]
),
]
),
)
Now I want to select some random buttons from the table and set an onPressed function on them. How can I proceed?
The safest place to store the button's "identity" be it first or 10th or 100th button is inside it.
class GameButton extends StatelessWidget {
final int id;
const GameButton({
this.id,
})
...
When the button is clicked , you want that info in the very moment of the click - let's make button tell us this info:
class GameButton extends StatelessWidget {
final int id;
final Function(int) onPressed;
const GameButton({
this.id,
this.onPressed,
})
...
Mind the Function(int) onPressed
added here - it's a callback which passes out an integer, we'll call it when the button is clicked and let the button pass it's id
to this function:
class GameButton extends StatelessWidget {
final int id;
final Function(int) onPressed;
const GameButton({this.id, this.onPressed});
@override
Widget build(BuildContext context) {
return FlatButton(
onPressed: () {
// on click, we pass id to onPressed(int)
onPressed(this.id);
},
child: null,
);
}
}
We'll define what to do with this id
when creating each button:
...
new GameButton(
id: id,
onPressed: onButtonClicked,
),
...
To create table of buttons you can first write them to List<TableRow>
, fill each row with desired number of buttons, and then set the whole list of rows as children
to Table
:
List<TableRow> buildButtons() {
// list for all rows
List<TableRow> rows = [];
// each button get's unique id
int id = 0;
for (var i = 0; i < widget.rows; i++) {
// new empty row
List<Widget> rowChildren = [];
// ---------------------- id incremented here
for (var y = 0; y < widget.cols; y++,id++) {
// fill row with buttons
rowChildren.add(
new GameButton(
id: id,
onPressed: onButtonClicked,
),
);
}
rows.add(new TableRow(children: rowChildren));
}
return rows;
}
And here is the handler:
onButtonClicked(int id) {
// this id ^ variable is the one coming from any clicked button
// use it e.g. to compare with any other variables from State
print("clicked button $id");
}
This is the code to get random number:
int max = widget.rows * widget.cols - 1;
this.randomSelection =
Random.secure().nextInt(max);
Final result might look like :
import 'package:flutter/material.dart';
import 'dart:math';
class ButtonTable extends StatefulWidget {
final int rows;
final int cols;
const ButtonTable({Key key, this.rows: 6, this.cols: 4}) : super(key: key);
get max => rows * cols - 1;
@override
_ButtonTableState createState() => _ButtonTableState();
}
class _ButtonTableState extends State<ButtonTable> {
int randomNumber = -1;
List<int> pot;
List<int> crossedNumbers;
List<int> initialTicket;
String resultText = "";
String statusText = "Roll it";
@override
void initState() {
super.initState();
restart();
}
void restart() {
initialTicket = generateTicket();
pot = List.generate(widget.max, (index) => index);
crossedNumbers = [];
randomNumber = -1;
}
List<int> generateTicket() {
var temp = List.generate(widget.max, (index) => index);
List<int> ticket = [];
for (int i = 0; i < widget.max / 2; i++) {
final randomIndex = Random.secure().nextInt(temp.length);
ticket.add(temp.removeAt(randomIndex));
}
return ticket;
}
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
new Table(
border: TableBorder.all(),
children: buildButtons(),
),
Text("$statusText"),
Text("$resultText"),
Center(
child: Row(
children: <Widget>[
FlatButton(
color: Colors.grey,
onPressed: rollNext,
child: Text("Roll"),
),
FlatButton(
color: Colors.grey,
onPressed: () {
setState(() {
restart();
});
},
child: Text("Restart")),
],
),
),
Text("Pot:" + pot.toString())
],
));
}
onButtonClicked(id) {
setState(() {
if (id == randomNumber) {
if (isNumberPlaying(id)) {
resultText = Random.secure().nextBool() ? "Housie" : "Whoo";
statusText = "Pull next number";
crossedNumbers.add(id);
} else {
resultText = Random.secure().nextBool()
? "You can't cheat machine code"
: "Nice try, but you don't have it on your ticket!";
}
} else {
resultText =
Random.secure().nextBool() ? "Missed, are u ok?" : "Try harder";
}
});
}
List<TableRow> buildButtons() {
List<TableRow> rows = [];
int id = 0;
for (var i = 0; i < widget.rows; i++) {
// new empty row
List<Widget> rowChildren = [];
for (var y = 0; y < widget.cols; y++, id++) {
// fill row with buttons
rowChildren.add(
new GameButton(
id: id,
playing: isNumberPlaying(id),
crossed: isCrossed(id),
onPressed: onButtonClicked,
),
);
}
rows.add(new TableRow(children: rowChildren));
}
return rows;
}
rollNext() {
setState(() {
if (pot.length > 0) {
int randomIndex = Random.secure().nextInt(pot.length);
this.randomNumber = pot.removeAt(randomIndex);
this.statusText = "Rolled: $randomNumber";
this.resultText = "playing one more time...";
} else {
restart();
}
});
}
isNumberPlaying(int id) {
return initialTicket.contains(id);
}
isCrossed(int id) {
return crossedNumbers.contains(id);
}
}
class GameButton extends StatelessWidget {
final int id;
final Function(int) onPressed;
final bool playing;
final bool crossed;
const GameButton({
Key key,
this.id,
this.onPressed,
this.playing,
this.crossed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return FlatButton(
color: decideColor(),
onPressed: () {
onPressed(this.id);
},
child: Stack(
children: <Widget>[
Visibility(
visible: crossed,
child: Icon(
Icons.done,
size: 48,
color: Colors.brown,
)),
decideText()
],
),
);
}
Color decideColor() {
// if id is not active = white
if (!this.playing)
return Colors.white;
else if (this.crossed) {
return Colors.yellow;
}
}
decideText() {
return Text(
playing ? "$id" : '',
style: TextStyle(
color: crossed ? Colors.green : Colors.black,
fontWeight: crossed ? FontWeight.bold : FontWeight.normal,
),
);
}
}
Have fun
I don't get your question clearly, Can you explain it more ? but you can change buttons color like this.
declare a variable : bool didColourChange = false;
FlatButton(
color: didColourChange ? Colors.red: Colors.green,
onPressed: () {
setState(() {
didColourChange = !didColourChange;
});
},
)
If you wanted to add some animations, you can use AnimatedContainer widget together with GestureDetector instead of using FlatButton
widget.
To avoid hard coding your children
, you might want to use the map method ofList class but that's only applicable if you're storing your numbers inside a list.
Here's the output:
Here's the full code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<List<int>> someListsOfNumbers = [
List.generate(4, (int idx) => idx),
List.generate(4, (int idx) => idx + 4),
List.generate(4, (int idx) => idx + 8),
];
Map<int, bool> pressedValues = Map.fromIterable(
List.generate(12, (int idx) => idx),
key: (item) => item,
value: (item) => false,
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: new Container(
child: new Table(
border: TableBorder.all(),
children: someListsOfNumbers.map(
(List<int> someList) => TableRow(
children: someList.map((int val) => GestureDetector(
onTap: (){
setState((){
pressedValues[val] = !pressedValues[val];
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 700),
height: 56.0,
color: pressedValues[val] ? Colors.red : Colors.green,
child: Center(
child: pressedValues[val] ? Text(val.toString()) : Text(""),
)
)
)
).toList()
)
).toList()
)
)
);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.