En la versió anterior, els textos es sobreposaven d'una manera senzilla. Ara anem a fer-ho d'una forma més professional, creant un giny (Sobreposat) que els defineixi. Aquest giny contemplarà dues línies de text (títol i subtitol).
A la carpeta widgets, creem el fitxer sobreposat.dart.
sobreposat.dart
import 'package:flutter/material.dart';
class Sobreposat extends StatelessWidget {
const Sobreposat({super.key, required this.title, required this.subtitle});
final String title;
final String subtitle;
@override
Widget build(BuildContext context) {
return Container(
alignment: const Alignment(0, -0.15),
child: IgnorePointer(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
title,
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 16),
Text(subtitle, style: Theme.of(context).textTheme.headlineSmall)
],
),
),
);
}
}
Ara hem de substituir els textos pel nou giny.
game_app.dart
import 'package:flame/game.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:joc_breakout/core/colors.dart'; import '../breakout.dart'; import '../config.dart'; import 'sobreposat.dart';
class GameApp extends StatefulWidget {
const GameApp({super.key});
@override
State<GameApp> createState() => _GameAppState();
}
class _GameAppState extends State<GameApp> {
late final Breakout game;
@override
void initState() {
super.initState();
game = Breakout();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
textTheme: GoogleFonts.pressStart2pTextTheme().apply(
bodyColor: ColorsApp.tema,
displayColor: ColorsApp.tema, // Color del text
),
),
home: Scaffold(
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: ColorsApp.gradient, // Gradient del marc
),
),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Center(
child: Column(
children: [
Expanded(
child: FittedBox(
child: SizedBox(
width: gameWidth,
height: gameHeight,
child: GameWidget(
game: game,
overlayBuilderMap: {
PlayState.inici.name: (context, game) =>
const Sobreposat(
title: 'PICA PER COMENÇAR',
subtitle: 'Empra les fletxes o fes lliscar',
),
PlayState.fi.name: (context, game) =>
const Sobreposat(
title: 'F I D E L J O C',
subtitle: 'Pica per tornar a jugar',
),
PlayState.guanya.name: (context, game) =>
const Sobreposat(
title: 'H A S G U A N Y A T !',
subtitle: 'Pica per tornar a jugar',
),
}
)
)
)
),
],
),
),
),
),
),
),
);
}
}
Podem donar encara un cert toc especial als textos, si els posem alguna animació. En aquest cas, el títol apareix desplaçant-se cap avall i el subtítol es manté en un bucle de repetició en el qual va apareixent i desapareixent de manera suau.
sobreposat.dart
import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart';
class Sobreposat extends StatelessWidget {
const Sobreposat({super.key, required this.title, required this.subtitle});
final String title;
final String subtitle;
@override
Widget build(BuildContext context) {
return Container(
alignment: const Alignment(0, -0.15),
child: IgnorePointer(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
title,
style: Theme.of(context).textTheme.headlineLarge,
).animate().slideY(duration: 750.ms, begin: -3, end: 0),
const SizedBox(height: 16),
Text(subtitle, style: Theme.of(context).textTheme.headlineSmall)
.animate(onPlay: (controller) => controller.repeat())
.fadeIn(duration: 1.seconds)
.then()
.fadeOut(duration: 1.seconds),
],
),
),
);
}
}

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