void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Responsive App',
theme: ThemeData(
primarySwatch: Colors.teal,
fontFamily: 'Roboto',
appBarTheme: const AppBarTheme(
backgroundColor: Colors.teal,
elevation: 0,
centerTitle: true,
iconTheme: IconThemeData(color: Colors.white),
),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: Colors.white,
selectedItemColor: Colors.teal,
unselectedItemColor: Colors.grey,
elevation: 8,
),
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _selectedIndex = 0;
final List<Widget> _pages = [
const ResponsiveLayoutPage(),
const ProfilePage(),
const SettingPage(),
];
void _onItemTapped(int index) {
setState(() => _selectedIndex = index);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
title: Text(
_selectedIndex == 0
? "Dashboard"
: _selectedIndex == 1
? "Profil Saya"
: "Pengaturan",
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
actions: [
IconButton(
icon: const Icon(Icons.notifications_none),
onPressed: () {},
),
const SizedBox(width: 8),
],
),
body: _pages[_selectedIndex],
bottomNavigationBar: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, -5),
),
],
),
child: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.dashboard_rounded),
label: "Dashboard",
),
BottomNavigationBarItem(
icon: Icon(Icons.person_rounded),
label: "Profil",
),
BottomNavigationBarItem(
icon: Icon(Icons.settings_rounded),
label: "Setting",
),
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
),
);
}
}
class ResponsiveLayoutPage extends StatelessWidget {
const ResponsiveLayoutPage({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return _buildWideLayout(context);
} else {
return _buildNarrowLayout(context);
}
},
);
}
Widget _buildWideLayout(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Konten Utama",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.teal,
),
),
const SizedBox(height: 16),
const Text(
"Selamat datang di aplikasi Flutter! Jelajahi berbagai fitur yang tersedia.",
style: TextStyle(fontSize: 16, color: Colors.grey),
),
const SizedBox(height: 30),
Center(
child: Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.network(
"https://picsum.photos/600/300",
width: 500,
height: 250,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => Container(
width: 500,
height: 250,
color: Colors.grey[300],
child: const Icon(Icons.error),
),
),
),
),
),
const SizedBox(height: 30),
// Responsive feature cards
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 800) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: _buildFeatureCards(),
);
} else {
return Wrap(
spacing: 16,
runSpacing: 16,
alignment: WrapAlignment.center,
children: _buildFeatureCards(),
);
}
},
),
const SizedBox(height: 30),
// Tombol untuk halaman kedua
Center(
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.teal,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 2,
),
onPressed: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
const SecondPage(),
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
const begin = Offset(1.0, 0.0);
const end = Offset.zero;
const curve = Curves.easeInOut;
var tween = Tween(begin: begin, end: end)
.chain(CurveTween(curve: curve));
var fadeTween = Tween<double>(begin: 0.0, end: 1.0);
return SlideTransition(
position: animation.drive(tween),
child: FadeTransition(
opacity: animation.drive(fadeTween),
child: child,
),
);
},
),
);
},
icon: const Icon(Icons.arrow_forward_rounded),
label: const Text("Pergi ke Halaman Kedua"),
),
),
],
),
);
}
Widget _buildNarrowLayout(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Konten Utama",
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Colors.teal,
),
),
const SizedBox(height: 12),
const Text(
"Selamat datang di aplikasi Flutter! Jelajahi berbagai fitur yang tersedia.",
style: TextStyle(fontSize: 15, color: Colors.grey),
),
const SizedBox(height: 20),
Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.network(
"https://picsum.photos/400/200",
width: double.infinity,
height: 180,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => Container(
height: 180,
color: Colors.grey[300],
child: const Icon(Icons.error),
),
),
),
),
const SizedBox(height: 20),
const Text(
"Fitur Utama",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
// Responsive feature cards for mobile
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 400) {
return Wrap(
spacing: 16,
runSpacing: 16,
alignment: WrapAlignment.center,
children: _buildFeatureCards(),
);
} else {
return Column(
children: _buildFeatureCards()
.map((card) => Padding(
padding: const EdgeInsets.only(bottom: 12),
child: card,
))
.toList(),
);
}
},
),
const SizedBox(height: 20),
// Tombol untuk halaman kedua di mobile
Center(
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.teal,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 2,
),
onPressed: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
const SecondPage(),
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
const begin = Offset(1.0, 0.0);
const end = Offset.zero;
const curve = Curves.easeInOut;
var tween = Tween(begin: begin, end: end)
.chain(CurveTween(curve: curve));
var fadeTween = Tween<double>(begin: 0.0, end: 1.0);
return SlideTransition(
position: animation.drive(tween),
child: FadeTransition(
opacity: animation.drive(fadeTween),
child: child,
),
);
},
),
);
},
icon: const Icon(Icons.arrow_forward_rounded),
label: const Text("Pergi ke Halaman Kedua"),
),
),
],
),
);
}
List<Widget> _buildFeatureCards() {
return [
FeatureCard(
icon: Icons.speed,
title: "Performa",
subtitle: "Monitor aplikasi",
),
FeatureCard(
icon: Icons.security,
title: "Keamanan",
subtitle: "Proteksi data",
),
FeatureCard(
icon: Icons.storage,
title: "Penyimpanan",
subtitle: "Kelola file",
),
FeatureCard(
icon: Icons.settings,
title: "Pengaturan",
subtitle: "Kustomisasi",
),
];
}
}
class FeatureCard extends StatelessWidget {
final IconData icon;
final String title;
final String subtitle;
const FeatureCard({
super.key,
required this.icon,
required this.title,
required this.subtitle,
});
@override
Widget build(BuildContext context) {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Container(
width: 120,
padding: const EdgeInsets.all(12),
child: Column(
children: [
Icon(icon, size: 32, color: Colors.teal),
const SizedBox(height: 8),
Text(
title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
textAlign: TextAlign.center,
),
Text(
subtitle,
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
textAlign: TextAlign.center,
),
],
),
),
);
}
}
class ProfilePage extends StatelessWidget {
const ProfilePage({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final bool isWide = constraints.maxWidth > 600;
return SingleChildScrollView(
padding: EdgeInsets.all(isWide ? 40 : 20),
child: Column(
children: [
const SizedBox(height: 20),
const CircleAvatar(
radius: 60,
backgroundImage: NetworkImage("https://picsum.photos/200"),
),
const SizedBox(height: 20),
const Text(
"Reihan Novalendra H",
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
"reihan.novalendra@example.com",
style: TextStyle(fontSize: 16, color: Colors.grey),
),
const SizedBox(height: 30),
// Responsive profile cards
if (isWide)
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: _buildProfileCard1(),
),
const SizedBox(width: 20),
Expanded(
child: _buildProfileCard2(),
),
],
)
else
Column(
children: [
_buildProfileCard1(),
const SizedBox(height: 20),
_buildProfileCard2(),
],
),
],
),
);
},
);
}
Widget _buildProfileCard1() {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_ProfileItem(Icons.person, "Informasi Pribadi"),
_ProfileItem(Icons.lock, "Keamanan Akun"),
_ProfileItem(Icons.payment, "Metode Pembayaran"),
_ProfileItem(Icons.language, "Bahasa"),
],
),
),
);
}
Widget _buildProfileCard2() {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_ProfileItem(Icons.help, "Pusat Bantuan"),
_ProfileItem(Icons.feedback, "Berikan Masukan"),
_ProfileItem(Icons.info, "Tentang Aplikasi"),
],
),
),
);
}
}
class _ProfileItem extends StatelessWidget {
final IconData icon;
final String title;
const _ProfileItem(this.icon, this.title);
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(icon, color: Colors.teal),
title: Text(title),
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
onTap: () {},
);
}
}
class SettingPage extends StatelessWidget {
const SettingPage({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final bool isWide = constraints.maxWidth > 600;
return SingleChildScrollView(
padding: EdgeInsets.all(isWide ? 40 : 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Pengaturan",
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
// Responsive settings layout
if (isWide)
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(child: _buildSettingsCard1()),
const SizedBox(width: 20),
Expanded(child: _buildSettingsCard2()),
const SizedBox(width: 20),
Expanded(child: _buildSettingsCard3()),
],
)
else
Column(
children: [
_buildSettingsCard1(),
const SizedBox(height: 20),
_buildSettingsCard2(),
const SizedBox(height: 20),
_buildSettingsCard3(),
],
),
],
),
);
},
);
}
Widget _buildSettingsCard1() {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_SettingItem(
Icons.notifications,
"Notifikasi",
"Kelola notifikasi aplikasi",
),
_SettingItem(
Icons.privacy_tip,
"Privasi",
"Kelola data dan privasi",
),
_SettingItem(
Icons.storage,
"Penyimpanan",
"Penggunaan penyimpanan",
),
],
),
),
);
}
Widget _buildSettingsCard2() {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_SettingItem(
Icons.language,
"Bahasa",
"Pilih bahasa aplikasi",
),
_SettingItem(
Icons.dark_mode,
"Tema Gelap",
"Aktifkan tema gelap",
isSwitch: true,
),
_SettingItem(
Icons.wallpaper,
"Tampilan",
"Kustomisasi tampilan",
),
],
),
),
);
}
Widget _buildSettingsCard3() {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_SettingItem(
Icons.help,
"Bantuan & Dukungan",
"Dapatkan bantuan",
),
_SettingItem(
Icons.info,
"Tentang Aplikasi",
"Versi 1.0.0",
),
],
),
),
);
}
}
class _SettingItem extends StatelessWidget {
final IconData icon;
final String title;
final String subtitle;
final bool isSwitch;
const _SettingItem(
this.icon,
this.title,
this.subtitle, {
this.isSwitch = false,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(icon, color: Colors.teal),
title: Text(title),
subtitle: Text(subtitle),
trailing: isSwitch
? Switch(
value: true,
onChanged: (value) {},
activeColor: Colors.teal,
)
: const Icon(Icons.arrow_forward_ios, size: 16),
onTap: () {},
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green[50],
appBar: AppBar(
title: const Text("Halaman Kedua"),
),
body: LayoutBuilder(
builder: (context, constraints) {
final bool isWide = constraints.maxWidth > 600;
return Center(
child: SingleChildScrollView(
padding: EdgeInsets.all(isWide ? 40 : 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Card(
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.network(
"https://picsum.photos/250/250",
width: isWide ? 300 : 200,
height: isWide ? 300 : 200,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) =>
Container(
width: isWide ? 300 : 200,
height: isWide ? 300 : 200,
color: Colors.grey[300],
child: const Icon(Icons.error),
),
),
),
),
const SizedBox(height: 30),
Text(
"Halaman Kedua",
style: TextStyle(
fontSize: isWide ? 28 : 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
Padding(
padding: EdgeInsets.symmetric(
horizontal: isWide ? 100 : 40),
child: const Text(
"Ini adalah halaman kedua aplikasi dengan desain yang lebih menarik dan modern.",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16, color: Colors.grey),
),
),
const SizedBox(height: 30),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.teal,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 3,
),
onPressed: () => Navigator.pop(context),
icon: const Icon(Icons.arrow_back),
label: const Text("Kembali ke Halaman Utama"),
),
],
),
),
);
},
),
);
}
}
Komentar
Posting Komentar