はじめに
前回までの記事の続きです。ページ単位での管理、リファクタリングを実施しました。
成果物
ソースコード
ディレクトリ構成
~/develop/pokemon_battle_app$ tree lib
lib
├── data
│ └── sample_data.dart
├── main.dart
├── models
│ └── pokemon.dart
├── page
│ ├── battle.dart
│ ├── home.dart
│ └── info.dart
└── router.dart
4 directories, 7 files
main.go
import 'package:flutter/material.dart';
import 'router.dart';
void main() {
runApp(PokemonApp());
}
class PokemonApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Pokemon App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routerConfig: router,
);
}
}
ここではrouterを呼び出しているだけです。
lib/router.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'page/battle.dart';
import 'page/home.dart';
import 'page/info.dart';
final GoRouter router = GoRouter(
routes: <RouteBase>[
ShellRoute(
builder: (context, state, child) {
return ScaffoldWithNavBar(child: child);
},
routes: <RouteBase>[
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) {
return HomePage();
},
),
GoRoute(
path: '/search',
builder: (BuildContext context, GoRouterState state) {
return BattlePage();
},
),
GoRoute(
path: '/info',
builder: (BuildContext context, GoRouterState state) {
return InfoPage();
},
),
],
),
],
);
class ScaffoldWithNavBar extends StatefulWidget {
final Widget child;
ScaffoldWithNavBar({required this.child});
@override
_ScaffoldWithNavBarState createState() => _ScaffoldWithNavBarState();
}
class _ScaffoldWithNavBarState extends State<ScaffoldWithNavBar> {
int _selectedIndex = 0;
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
switch (index) {
case 0:
context.go('/');
break;
case 1:
context.go('/search?query=example');
break;
case 2:
context.go('/info');
break;
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter App'),
),
body: widget.child,
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Info',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
lib/page/battle.dart
import 'package:flutter/material.dart';
import '../models/pokemon.dart';
import '../data/sample_data.dart';
class BattlePage extends StatelessWidget {
final Pokemon pokemon1 = pikachu;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pokemon Battle'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildPokemonInfo(pokemon1),
],
),
),
);
}
Widget _buildPokemonInfo(Pokemon pokemon) {
return Column(
children: [
Text(
pokemon.name,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
Image.network(pokemon.imageUrl, height: 100, width: 100),
Column(
children: pokemon.moves
.map((move) => Text('${move.name} (${move.power})'))
.toList(),
),
],
);
}
}
lib/models/pokemon.dart
class Pokemon {
final String name;
final String imageUrl;
final List<Move> moves;
Pokemon({required this.name, required this.imageUrl, required this.moves});
}
class Move {
final String name;
final int power;
Move({required this.name, required this.power});
}
lib/data/sample_data.dart
import '../models/pokemon.dart';
final pikachu = Pokemon(
name: 'ピカチュウ',
imageUrl:
'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png',
moves: [
Move(name: 'Thunderbolt', power: 90),
Move(name: 'Quick Attack', power: 40),
Move(name: 'Iron Tail', power: 100),
Move(name: 'Electro Ball', power: 80),
],
);
final charmander = Pokemon(
name: 'ヒトカゲ',
imageUrl:
'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png',
moves: [
Move(name: 'Flamethrower', power: 90),
Move(name: 'Scratch', power: 40),
Move(name: 'Dragon Breath', power: 60),
Move(name: 'Fire Spin', power: 35),
],
);
