Per començar, crearem un taulell de tres per tres caselles, que serà on més endavant es desenvoluparà el joc. Inicialment cada casella contindrà els seus índex (filera i columna) per poder comprovar que ho estem fent bé.
Posarem el projecte a la carpeta tres_linia.
El programa principal només té l'esquelet amb una barra que conté el títol i carrega la pantalla principal. Hem definit els colors i els estils en un fitxer separat, com comentarem una mica més endavant.
main.dart
import 'package:flutter/material.dart'; import 'package:tres_linia/core/colors.dart'; import 'package:tres_linia/screens/pant_principal.dart';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Tres en línia"),
backgroundColor: ColorsApp.primari,
foregroundColor: ColorsApp.text,
),
backgroundColor: ColorsApp.fons,
body: PantPral(),
),
);
}
}
L'element més important del programa és la casella, que hem creat com un element genèric que podrem utilitzar diversos cops. L'hem posat al fitxer casella.dart, que està a la carpeta components.
Cada casella té dos paràmetres, que corresponen a les seves coordenades. És només un element en forma de rectangle amb els costats arrodonits que conté un text que indica les seves coordenades.
casella.dart
import 'package:flutter/material.dart'; import 'package:tres_linia/core/colors.dart'; import 'package:tres_linia/core/estils.dart';
class Casella extends StatefulWidget {
final int posX;
final int posY;
const Casella({super.key, required this.posX, required this.posY});
@override
State<Casella> createState() => _CasellaState();
}
class _CasellaState extends State<Casella> {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 30, bottom: 20, left: 8, right: 8),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: ColorsApp.component,
borderRadius: BorderRadius.circular(12)
),
child: Padding(
padding: const EdgeInsets.all(25.0),
child: Text(
"${widget.posX} ${widget.posY}",
style: Estils.estilTextCaselles
),
)
),
);
}
}
La base de la pantalla principal seran tres fileres de tres caselles cada una, per això farem servir dos bucles. Atès que no s'admeten bucles de diverses línies (amb claus), cal fer els bucles en una sola línia. Per facilitar-ho, hem creat un mètode que retorna una filera de tres caselles i tenim un bucle principal que crea les tres fileres. Per complementar-ho, tenim una caixa que deixa una separació respecte a la barra superior i un element d'expandir que, de moment, té un text buit; per acabar d'omplir la resta de la pantalla.
pant_principal.dart
import 'package:flutter/material.dart'; import 'package:tres_linia/components/casella.dart';
class PantPral extends StatefulWidget {
const PantPral({super.key});
@override
State<PantPral> createState() => _PantPralState();
}
class _PantPralState extends State<PantPral> {
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
height: 20,
),
for(int i = 0; i < 3; i++) filera(i),
Expanded(child: Text(" "))
],
);
}
Row filera(int pY) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
for(int i = 0; i < 3; i++) Casella(posX: i, posY: pY),
],
);
}
}
Per acabar, ens falten els colors i els estils, que hem posat en fitxers de la carpeta core.
estils.dart
import 'package:flutter/material.dart'; import 'package:tres_linia/core/colors.dart';
class Estils {
static const TextStyle estilTextCaselles = TextStyle(
color: ColorsApp.text,
fontSize: 30,
fontWeight: FontWeight.bold,
);
}
colors.dart
import 'dart:ui';
class ColorsApp {
static const Color fons = Color(0xFF000000);
static const Color primari = Color(0xFF444444);
static const Color text = Color(0xFFFFFFFF);
static const Color component = Color(0xFF531C00);
}

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.