In this tutorial, we build a modern travel booking app UI using Flutter.
The design emphasises a premium look, featuring gradient headers, category chips, horizontal trip cards, and a detailed property screen.
This UI is inspired by real-world travel and rental apps, demonstrating clean layouts, reusable widgets, and smooth navigation.
Flutter Travel App UI – Complete Code Implementation
HomeScreenUI
import 'package:conteudo_local/app/data/services/api_service/app_imports.dart';
import 'package:flutter/material.dart';
class HomeScreenUI extends StatelessWidget {
const HomeScreenUI({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F5F5),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top Card with Search
Container(
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF161928),
Color(0xFF586378),
Color(0xFF262d3d),
],
),
borderRadius: BorderRadius.circular(30),
),
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Profile and notification
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Colors.black.withOpacity(.3),
width: 3,
),
),
child: CircleAvatar(
radius: 20,
backgroundColor: Colors.white,
child: ClipOval(
child: Image.network(
'https://i.pravatar.cc/150?img=5',
fit: BoxFit.cover,
width: 40,
height: 40,
),
),
),
),
const SizedBox(width: 12),
const Text(
'Hai, Magdalena!',
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
],
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Color(0xFF161928).withOpacity(.3),
width: 5,
),
),
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: Image.asset(
AppImages.notificationPngIcon,
height: 20,
),
),
),
],
),
const SizedBox(height: 30),
// Title
const Text(
'Where do\nyou want to go?',
style: TextStyle(
color: Colors.white,
fontSize: 32,
fontWeight: FontWeight.bold,
height: 1.2,
),
),
const SizedBox(height: 20),
// Search Bar
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
),
child: Padding(
padding: const EdgeInsets.only(left: 15.0),
child: TextField(
decoration: InputDecoration(
hintText: 'Search your destination point',
hintStyle: TextStyle(
color: Colors.grey[400],
fontSize: 14,
),
border: InputBorder.none,
suffixIcon: Container(
margin: const EdgeInsets.all(6),
// thoda gap for shadow
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: [
// dark shadow (bottom-right)
BoxShadow(
color: Colors.orange.withOpacity(0.5),
offset: const Offset(3, 3),
blurRadius: 10,
),
// light highlight (top-left)
BoxShadow(
color: Colors.white.withOpacity(0.9),
offset: const Offset(-2, -2),
blurRadius: 4,
),
],
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
AppImages.searchIcon,
height: 20,
),
),
),
contentPadding: const EdgeInsets.symmetric(
vertical: 15,
),
),
),
),
),
],
),
),
const SizedBox(height: 30),
// Travel Categories
const Text(
'Travel categories',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF2C3E50),
),
),
const SizedBox(height: 15),
SizedBox(
height: 60,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: [
buildCategoryChip('🎒', 'Trip', true),
const SizedBox(width: 10),
buildCategoryChip('🏖️', 'Staycation', false),
const SizedBox(width: 10),
buildCategoryChip('🏡', 'Stay In', false),
const SizedBox(width: 10),
buildCategoryChip('🌾🏡', 'Farm', false), // Farm House
const SizedBox(width: 10),
buildCategoryChip('🏘️✨', 'Villa', false), // Villa
],
),
),
// Top Trips
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Top trips',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF2C3E50),
),
),
TextButton(
onPressed: () {},
child: Row(
children: const [
Text(
'Explore',
style: TextStyle(color: Colors.grey, fontSize: 14),
),
SizedBox(width: 5),
Icon(Icons.arrow_forward, color: Colors.grey, size: 16),
],
),
),
],
),
const SizedBox(height: 15),
// Trip Cards
SizedBox(
height: 280,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
buildTripCard(
context,
'https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=400',
'Kalibata City',
'Apartment',
'\$150',
),
const SizedBox(width: 15),
buildTripCard(
context,
'https://images.unsplash.com/photo-1512917774080-9991f1c4c750?w=400',
'Linden Tower',
'Hotel',
'\$50',
),
const SizedBox(width: 15),
buildTripCard(
context,
'https://www.dellaresorts.com/new-images/enclave-ex-new-2-feb-1.webp',
'Luxury Enclave',
'Villa',
'\$50',
),
],
),
),
],
),
),
),
bottomNavigationBar: Container(
margin: const EdgeInsets.all(25),
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 5),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Image.asset(AppImages.homePngIcon, height: 28),
Image.asset(AppImages.direction, height: 28, color: Colors.grey),
Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFFF8C42), // orange
Color(0xFFFF6B35), // deep orange
],
),
boxShadow: [
// bottom-right shadow (depth)
BoxShadow(
color: Colors.black.withOpacity(0.25),
offset: const Offset(4, 4),
blurRadius: 10,
),
// top-left highlight (3D effect)
BoxShadow(
color: Colors.white.withOpacity(0.6),
offset: const Offset(-4, -4),
blurRadius: 10,
),
],
),
child: Image.asset(
AppImages.searchIcon,
height: 28,
color: Colors.white,
),
),
Image.asset(AppImages.disLikeIcon, height: 28, color: Colors.grey),
Stack(
children: [
Image.asset(AppImages.shop, height: 28, color: Colors.grey),
Positioned(
right: 0,
top: -4,
child: Container(
padding: const EdgeInsets.all(4),
decoration: const BoxDecoration(
color: Color(0xFFFF6B35),
shape: BoxShape.circle,
),
child: const Text(
'2',
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
),
),
);
}
Widget buildCategoryChip(String emoji, String label, bool isSelected) {
return Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8, left: 5),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: isSelected ? Colors.white : Colors.grey[200],
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isSelected ? Colors.transparent : Colors.grey[300]!,
),
boxShadow:
isSelected
? [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 3),
),
]
: [],
),
child: Row(
children: [
Text(emoji, style: const TextStyle(fontSize: 16)),
const SizedBox(width: 8),
Text(
label,
style: TextStyle(
color: isSelected ? const Color(0xFF2C3E50) : Colors.grey,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
fontSize: 14,
),
),
],
),
),
);
}
Widget buildTripCard(
BuildContext context,
String imageUrl,
String title,
String subtitle,
String price,
) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder:
(context) => DetailScreen(
imageUrl: imageUrl,
title: title,
subtitle: subtitle,
price: price,
),
),
);
},
child: Container(
width: 180,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
boxShadow: [
// main shadow (bottom)
BoxShadow(
color: Colors.black.withOpacity(0.5),
blurRadius: 18,
offset: const Offset(0, 10),
),
// soft ambient shadow
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 6,
offset: const Offset(0, 3),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.network(
imageUrl,
height: 160,
width: 160,
fit: BoxFit.cover,
),
),
),
),
Positioned(
top: 15,
right: 15,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.9),
borderRadius: BorderRadius.circular(10),
),
child: Text(
price,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12,
),
),
),
),
],
),
Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Color(0xFF2C3E50),
),
),
const SizedBox(height: 4),
Row(
children: [
Text(
subtitle,
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
),
const Spacer(),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: [
// dark shadow (bottom-right)
BoxShadow(
color: Colors.black.withOpacity(0.5),
offset: const Offset(3, 3),
blurRadius: 10,
),
// light highlight (top-left)
BoxShadow(
color: Colors.white.withOpacity(0.9),
offset: const Offset(-2, -2),
blurRadius: 4,
),
],
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
AppImages.disLikeIcon,
height: 20,
),
),
),
],
),
],
),
),
],
),
),
),
);
}
} DetailsUI
import 'package:conteudo_local/app/data/services/api_service/app_imports.dart';
import 'package:flutter/material.dart';
class DetailScreen extends StatelessWidget {
final String imageUrl;
final String title;
final String subtitle;
final String price;
const DetailScreen({
Key? key,
required this.imageUrl,
required this.title,
required this.subtitle,
required this.price,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F5F5),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Image with overlay
Stack(
children: [
Stack(
children: [
ClipRRect(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
),
child: Image.network(
imageUrl,
height: 600,
width: double.infinity,
fit: BoxFit.cover,
),
),
// 🔥 Black gradient overlay
Positioned.fill(
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomLeft,
colors: [
Colors.black.withOpacity(0.0), // top dark
Colors.transparent, // middle clear
Colors.black, // bottom dark
],
),
),
),
),
],
),
// Back button
Positioned(
top: 60,
left: 20,
child: GestureDetector(
onTap: () => Navigator.pop(context),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Color(0xFF161928).withOpacity(.3),
width: 5,
),
),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.9),
shape: BoxShape.circle,
),
child: const Icon(
Icons.arrow_back_ios_new,
color: Color(0xFF2C3E50),
size: 20,
),
),
),
),
),
// Bookmark button
Positioned(
top: 60,
right: 20,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Color(0xFF161928).withOpacity(.3),
width: 5,
),
),
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.9),
shape: BoxShape.circle,
),
child: Image.asset(
AppImages.disLikeIcon,
height: 20,
color: Colors.black87,
),
),
),
),
// Action buttons
Positioned(
bottom: 20,
right: 20,
child: Column(
children: [
buildActionButton(Icons.photo_library_outlined),
const SizedBox(height: 10),
buildActionButton(Icons.threed_rotation_rounded),
const SizedBox(height: 10),
buildActionButton(Icons.store_outlined),
],
),
),
// Title and price overlay
Positioned(
bottom: 20,
left: 20,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$subtitle\n$title',
style: const TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.bold,
height: 1.2,
shadows: [
Shadow(
color: Colors.black45,
offset: Offset(0, 2),
blurRadius: 5,
),
],
),
),
const SizedBox(height: 8),
Text(
'$price/month',
style: const TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
shadows: [
Shadow(
color: Colors.black45,
offset: Offset(0, 2),
blurRadius: 5,
),
],
),
),
],
),
),
],
),
// Overview section
Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Overview',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Color(0xFFFF8C45),
),
),
const SizedBox(height: 15),
Row(
children: [
buildSpecItem(
Icons.bed_outlined,
'2 bedroom',
'King size',
),
const SizedBox(width: 30),
buildSpecItem(
Icons.straighten_outlined,
'50 m²',
'Building area',
),
],
),
const SizedBox(height: 20),
Text(
'The Kalibata City Apartment is located in the midst of the hustle and bustle of Jakarta, and is touted as one of the most popular residences in the area.',
style: TextStyle(
color: Colors.black87,
fontSize: 14,
height: 1.6,
),
),
],
),
),
],
),
),
),
// Rent now button
Padding(
padding: const EdgeInsets.all(25),
child: SizedBox(
width: double.infinity,
height: 60,
child: Container(
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Color(0xFFF35904), // #f35904
Color(0xFFF79037), // #f79037
Color(0xFFf8963d), // #f79037
],
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
blurRadius: 10,
offset: const Offset(0, 6),
),
],
),
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'Rent now',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(width: 10),
Icon(Icons.arrow_forward, color: Colors.white),
],
),
),
),
),
),
],
),
);
}
Widget buildActionButton(IconData icon) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(color: Color(0xFF161928).withOpacity(.4), width: 4),
),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFF2C3E50).withOpacity(0.8),
borderRadius: BorderRadius.circular(12),
),
child: Icon(icon, color: Colors.white, size: 20),
),
);
}
Widget buildSpecItem(IconData icon, String title, String subtitle) {
return Row(
children: [
Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
// bottom shadow (depth)
BoxShadow(
color: Colors.black.withOpacity(0.25),
blurRadius: 8,
offset: const Offset(3, 4),
),
// top highlight (3D feel)
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 4,
offset: const Offset(-2, -2),
),
],
),
child: Center(
child: Icon(icon, color: const Color(0xFFFF8C42), size: 24),
),
),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Color(0xFF2C3E50),
),
),
Text(
subtitle,
style: TextStyle(color: Colors.grey[600], fontSize: 12),
),
],
),
],
);
}
} - Gradient-based header with search functionality
- Horizontal travel categories with selection state
- Reusable trip card widgets with image overlays
- Detailed property screen with hero-style image layout
- Clean spacing, shadows, and modern color palette
📌 Full source code is available on GitHub for easy reference and reuse.
.png)
0 Comments
Please Do Not Comments Any Span Or Span link..