Creating a Flutter Pokedex

Introduction and Theme

Starting with the app

Fetching first 250 Pokemon

<manifest xmlns:android...>
...
<uses-permission android:name="android.permission.INTERNET" />
<application ...
</manifest>
 flutter pub add http
class Pokemon {
int id;
String name;
String img;
Pokemon.fromJson(Map<String, dynamic> data)
: id = data['id'],
name = data['name'],
img = data['img'];
Map<String, dynamic> toJson() => {'id': id, 'name': name, 'img': img};
}
import 'dart:async';
import 'package:http/http.dart' as http;
class PokeAPI {
static Future<http.Response> getPokemon() =>
http.get(Uri.parse("https://pokeapi.co/api/v2/pokemon?limit=250"));
}
void getPokemonFromPokeApi() async {
PokeAPI.getPokemon().then((response) {
List<Map<String, dynamic>> data =
List.from(json.decode(response.body)['results']);
setState(() {
pokemon = data.asMap().entries.map<Pokemon>((element) {
element.value['id'] = element.key + 1;
element.value['img'] = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${element.key + 1}.png";
return Pokemon.fromJson(element.value);
}).toList();
});
});
}
class _HomeState extends State<Home> {
List<Pokemon> pokemon = List.empty();

@override
void initState() {
super.initState();
getPokemonFromPokeApi();
}
void getPokemonFromPokeApi() async {
.....

Showing data in GridView

import 'package:flutter/material.dart';
import 'package:pokedex/models/poke_model.dart';
import 'package:pokedex/widgets/pokemon_card.dart';
class PokemonGrid extends StatefulWidget {
final List<Pokemon> pokemon;
const PokemonGrid({Key? key, required this.pokemon}) : super(key: key);
@override
_PokemonGridState createState() => _PokemonGridState();
}
class _PokemonGridState extends State<PokemonGrid> {
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
final crossAxisCount = (width > 1000)
? 5
: (width > 700)
? 4
: (width > 450)
? 3
: 2;
return GridView.count(
padding: const EdgeInsets.all(7),
crossAxisCount: crossAxisCount,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
semanticChildCount: 250,
childAspectRatio: 200 / 244,
physics: const BouncingScrollPhysics(),
children: widget.pokemon
.map(
(pokemon) => PokemonCard(
id: pokemon.id,
name: pokemon.name,
image: pokemon.img,
),
)
.toList(),
);
}
}
final width = MediaQuery.of(context).size.width;
final crossAxisCount = (width > 1000)
? 5
: (width > 700)
? 4
: (width > 450)
? 3
: 2;
import 'package:flutter/material.dart';
import 'package:pokedex/widgets/pokemon_card_background.dart';
import 'package:pokedex/widgets/pokemon_card_data.dart';
class PokemonCard extends StatelessWidget {
final int id;
final String name;
final String image;
const PokemonCard({
Key? key,
required this.id,
required this.name,
required this.image,
}) : super(key: key);
BoxDecoration getContainerDecoration() => BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(7),
border: Border.all(
color: Colors.grey.withOpacity(0.24),
width: 1,
),
);
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(7),
decoration: getContainerDecoration(),
child: Stack(
children: [
PokemonCardBackground(id: id),
PokemonCardData(name: name, image: image),
],
),
);
}
}
import 'package:flutter/material.dart';class PokemonCardBackground extends StatelessWidget {
final int id;
const PokemonCardBackground({Key? key, required this.id}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(
"$id",
style: TextStyle(
fontSize: 101,
fontWeight: FontWeight.bold,
color: Colors.grey[200],
),
);
}
}
import 'package:flutter/material.dart';class PokemonCardData extends StatelessWidget {
final String image;
final String name;
const PokemonCardData({
Key? key,
required this.name,
required this.image,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: Image.network(
image,
fit: BoxFit.contain,
),
),
const Divider(),
Text(
"${name[0].toUpperCase()}${name.substring(1)}",
style: const TextStyle(
fontSize: 21,
color: Colors.black87,
),
),
],
);
}
}

Adding navigation to the application

import 'package:pokedex/screens/details.dart';
import 'package:pokedex/screens/home.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Pokedex',
theme: ThemeData(
primarySwatch: Colors.red,
),
initialRoute: "/",
routes: {
"/": (context) => const Home(),
"/details": (context) => const Details(),
},

);
}
}
import 'package:flutter/material.dart';
import 'package:pokedex/models/pokemon_screen_data.dart';
import 'package:pokedex/widgets/pokemon_card_background.dart';
import 'package:pokedex/widgets/pokemon_card_data.dart';
class PokemonCard extends StatelessWidget {
final int id;
final String name;
final String image;
const PokemonCard({
Key? key,
required this.id,
required this.name,
required this.image,
}) : super(key: key);
BoxDecoration getContainerDecoration() => BoxDecoration(
borderRadius: BorderRadius.circular(7),
border: Border.all(
color: Colors.grey.withOpacity(0.24),
width: 1,
),
);
@override
Widget build(BuildContext context) {
return Material(
color: Colors.white,
child: InkWell(
borderRadius: BorderRadius.circular(7),
enableFeedback: true,
splashColor: Colors.red[50],
onTap: () => {
Navigator.pushNamed(
context,
"/details",
arguments: PokemonScreenData(id, name, image),
)
},
child:
Container(
padding: const EdgeInsets.all(7),
decoration: getContainerDecoration(),
child: Stack(
children: [
PokemonCardBackground(id: id),
PokemonCardData(name: name, image: image),
],
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:pokedex/models/pokemon_screen_data.dart';
import 'package:pokedex/widgets/detail_back_button.dart';
import 'package:pokedex/widgets/detail_data.dart';
import 'package:pokedex/widgets/detail_image.dart';
import 'package:pokedex/widgets/detail_title.dart';
class Details extends StatelessWidget {
const Details({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final arguments =
ModalRoute.of(context)!.settings.arguments as PokemonScreenData;
return Scaffold(
backgroundColor: Colors.black,
body: SingleChildScrollView(
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
physics: const BouncingScrollPhysics(),
child: Column(
children: [
DetailImage(image: arguments.image),
DetailTitle(id: arguments.id, name: arguments.name),
DetailData(id: arguments.id),
],
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
floatingActionButton: const DetailBackButton(),
);
}
}
import 'package:flutter/material.dart';class DetailImage extends StatelessWidget {
final String image;
const DetailImage({Key? key, required this.image}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
constraints: const BoxConstraints(
maxHeight: 500,
),
color: Colors.black,
child: Center(
child: Stack(
children: [
Container(
height: 500,
width: 500,
decoration: const BoxDecoration(
color: Colors.white10,
shape: BoxShape.circle,
),
),
Image.network(
image,
fit: BoxFit.contain,
alignment: Alignment.center,
),
],
),
),
);
}
}
import 'package:flutter/material.dart';class DetailTitle extends StatelessWidget {
final int id;
final String name;
const DetailTitle({Key? key, required this.id, required this.name})
: super(key: key);
@override
Widget build(BuildContext context) {
return Chip(
backgroundColor: Colors.white,
label: Text(
"${name[0].toUpperCase()}${name.substring(1)}",
style: const TextStyle(
fontSize: 24,
color: Colors.black,
),
),
avatar: CircleAvatar(
child: Text(
id.toString(),
),
),
);
}
}
import 'package:flutter/material.dart';class DetailData extends StatelessWidget {
final int id;
const DetailData({Key? key, required this.id}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width,
minHeight: 500,
),
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
width: 2,
color: Colors.grey,
),
),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(71),
topRight: Radius.circular(71),
),
),
child: Column(
children: [],
),
);
}
}
import 'package:flutter/material.dart';class DetailBackButton extends StatelessWidget {
const DetailBackButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return FloatingActionButton.extended(
onPressed: () => Navigator.pop(context),
tooltip: 'Share',
label: const Text(
"Back",
),
icon: const Icon(Icons.arrow_back_ios_new_rounded),
);
}
}

Thank You 🙏and Merry Christmas 🎄!

--

--

--

A student developer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

What is the difference between the “Salesforce” and “Salesforce Platform” licenses?

Learn Pytorch

Software Teams and Where We Fit In

Delivering the Right Infrastructure for the Right Job

Using SQL Server Pass-Thru in R to Query and Join Tables Across Servers

Docker 20.10 on ARM/V7 Buster is… bust

Create a simple table using SQLAlchemy and enable autogeneration by Alembic

Initial structure of the project.

Build your own DSL with Go & HCL

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Om Londhe

Om Londhe

A student developer

More from Medium

How to Use a Ternary Operator with Multiple Condition In Flutter?

Navigator overview in Flutter.

Post image

Flutter — Adaptive Layout

Stream Location in Flutter