Flutter adalah framework yang sangat powerful untuk membuat aplikasi mobile dengan tampilan modern dan responsif. Pada artikel ini, kita akan membuat sebuah aplikasi sederhana yang menampilkan daftar film Marvel Cinematic Universe (MCU) Phase 1, lengkap dengan fitur pencarian, detail film, serta navigasi menggunakan BottomNavigationBar.
___________________________________________________________________________________
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: MainScreen(),
));
}
// ========== MAIN SCREEN DENGAN NAVIGASI ==========
class MainScreen extends StatefulWidget {
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
int _selectedIndex = 0;
final List<Widget> _pages = [
JadwalBioskop(),
ProfilePage(),
AboutPage(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: _pages[_selectedIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
backgroundColor: Colors.blue[900],
selectedItemColor: Colors.white,
unselectedItemColor: Colors.grey[300],
onTap: _onItemTapped,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.movie),
label: "Film",
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: "Profil",
),
BottomNavigationBarItem(
icon: Icon(Icons.info),
label: "Tentang",
),
],
),
);
}
}
// ========== HALAMAN 1: DAFTAR FILM ==========
class JadwalBioskop extends StatefulWidget {
@override
State<JadwalBioskop> createState() => _JadwalBioskopState();
}
class _JadwalBioskopState extends State<JadwalBioskop> {
List<Map<String, String>> filmList = [
{ "judul": "iron man (2008)", "genre": "Action/Sci-fi", "poster": "https://upload.wikimedia.org/wikipedia/id/7/70/Ironmanposter.JPG", "deskripsi": "After being held captive in an Afghan cave, billionaire engineer Tony Stark creates a unique weaponized suit of armor to fight evil." }, { "judul": "The Incredible Hulk", "genre": "Action/Sci-fi", "poster": "https://upload.wikimedia.org/wikipedia/id/e/e6/Hulk_poster.jpg", "deskripsi": "Bruce Banner terus berlari dari masa lalunya sebagai monster hijau penghancur. Tapi ketika musuh baru muncul dan kekasihnya, Betty Ross, terancam, ia harus memilih: tetap bersembunyi atau melepaskan Hulk untuk pertarungan terbesar" }, { "judul": "iron man 2", "genre": "Action/Sci-fi", "poster": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQDE3oRYVxUXqKI0urYBJz2R1MIoyqWfZkLCA&s", "deskripsi": "Dunia tahu Tony Stark adalah Iron Man, tapi kekuasaannya diuji saat racun dalam darahnya dan Ivan Vanko, musuh yang membenci warisan keluarga Stark, muncul. Di antara pesta, persaingan, dan bahaya, bisakah Tony bertahan sebelum semuanya meledak?" }, { "judul": "thor", "genre": "Romance, Drama", "poster": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSFLwsvcOEwRt19o0NQpy9MsAmAmnFaq-9hTw&s", "deskripsi": "Diusir dari Asgard karena kesombongannya, Thor—dewa petir yang perkasa—harus belajar kerendahan hati di Bumi. Namun, ketika ancaman gelap mengintai kedua dunianya, ia harus membuktikan diri sebagai pahlawan sejati. Dengan palu ajaibnya yang hilang, akankah Thor bangkit sebelum segalanya hancur?" }, { "judul": "Captain America: The First Avenger (2011)", "genre": "Action, Sci-fi", "poster": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSmUYQ1HSR0LYERmnBJOq8MjGlpy5hZZXOtUQ&s" }, { "judul": "The Avengers", "genre": "Action,sci fi", "poster": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT3SGI0tAFu9WIM7wh6fCSUPlPHootZDtB3nA&s", "deskripsi": "Loki, sang dewa penipu, kembali dengan pasukan aliennya untuk menaklukkan Bumi, dan satu-satunya harapan umat manusia terletak pada para pahlawan terkuat di planet ini. Iron Man, Captain America, Thor, Hulk, Black Widow, dan Hawkeye harus belajar bekerja sama sebagai tim untuk menghentikan ancaman yang tak pernah terbayangkan. Dengan aksi spektakuler, humor khas Marvel, dan pertarungan epik di jantung New York, adalah film yang tak boleh Anda lewatkan. Bisakah mereka menyelamatkan dunia sebelum semuanya terlambat?" }, ];
String searchQuery = "";
void detailFilm(Map<String, String> film) {
showDialog(
context: context,
builder: (context) {
return Dialog(
backgroundColor: Colors.grey[900],
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: SingleChildScrollView(
child: Column(
children: [
ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
child: Image.network(film["poster"]!, fit: BoxFit.cover),
),
Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(film["judul"]!,
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white)),
const SizedBox(height: 4),
Text(film["genre"]!, style: const TextStyle(color: Colors.white70)),
const SizedBox(height: 12),
Text(film["deskripsi"] ?? "Tidak ada deskripsi",
style: const TextStyle(color: Colors.white)),
const SizedBox(height: 16),
Align(
alignment: Alignment.centerRight,
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.red[900]),
onPressed: () => Navigator.pop(context),
child: const Text("Keluar", style: TextStyle(color: Colors.white)),
),
),
],
),
),
],
),
),
);
},
);
}
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
List<Map<String, String>> filteredList = filmList
.where((film) => film["judul"]!.toLowerCase().contains(searchQuery.toLowerCase()))
.toList();
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text("MCU - PHASE 1", style: TextStyle(fontWeight: FontWeight.bold)),
backgroundColor: Colors.blue[900],
),
body: Column(
children: [
// Search bar
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
onChanged: (value) => setState(() => searchQuery = value),
style: const TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: "Cari judul film...",
hintStyle: const TextStyle(color: Colors.grey),
prefixIcon: const Icon(Icons.search, color: Colors.white),
filled: true,
fillColor: Colors.grey[900],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide.none,
),
),
),
),
// Daftar film
Expanded(
child: GridView.builder(
padding: const EdgeInsets.all(12),
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: width < 420 ? 360 : 240,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.55,
),
itemCount: filteredList.length,
itemBuilder: (context, index) {
var film = filteredList[index];
return Card(
color: Colors.grey[900],
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: InkWell(
onTap: () => detailFilm(film),
child: ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
child: Image.network(film["poster"]!,
fit: BoxFit.cover, width: double.infinity),
),
),
),
Padding(
padding: const EdgeInsets.all(8),
child: Text(
film["judul"]!,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
)
],
),
);
},
),
),
],
),
);
}
}
// ========== HALAMAN 2: PROFIL ==========
class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(title: const Text("Profil"), backgroundColor: Colors.blue[900]),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CircleAvatar(
radius: 50,
backgroundImage: NetworkImage("https://i.pravatar.cc/300"),
),
SizedBox(height: 16),
Text("Caca ardiansyah", style: TextStyle(color: Colors.white, fontSize: 20)),
SizedBox(height: 8),
Text("caca.ardiansyah96@smk.belajar.id", style: TextStyle(color: Colors.grey)),
],
),
),
);
}
}
// ========== HALAMAN 3: TENTANG ==========
class AboutPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(title: const Text("Tentang Aplikasi"), backgroundColor: Colors.blue[900]),
body: const Center(
child: Padding(
padding: EdgeInsets.all(16),
child: Text(
"Aplikasi ini menampilkan daftar film MCU Phase 1.\n\nDibuat dengan Flutter.",
style: TextStyle(color: Colors.white, fontSize: 16),
textAlign: TextAlign.center,
),
),
),
);
}
}
Komentar
Posting Komentar