Flutter Travel App. Ideal template for listing, social media, and e-commerce applications.
Creating a travel app UI using Flutter involves designing screens like the home screen, destination details, booking screens, and more. Below is an example of how you can start building a simple travel app UI in Flutter.
Prerequisites
Ensure you have Flutter installed and set up on your machine. You can follow the official Flutter installation guide to get started.
Step 1: Setting Up the Project
- Create a new Flutter project:
flutter create travel_app cd travel_app
- Open the project in your preferred IDE (e.g., VSCode, Android Studio).
Step 2: Designing the Home Screen
Let’s start with a basic home screen that displays a list of popular destinations.
lib/main.dart
:
import 'package:flutter/material.dart';
void main() {
runApp(TravelApp());
}
class TravelApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Travel App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
final List<Map<String, String>> destinations = [
{
'name': 'Paris',
'image': 'https://example.com/paris.jpg',
},
{
'name': 'New York',
'image': 'https://example.com/newyork.jpg',
},
{
'name': 'Tokyo',
'image': 'https://example.com/tokyo.jpg',
},
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Travel App'),
),
body: ListView.builder(
itemCount: destinations.length,
itemBuilder: (context, index) {
return DestinationCard(
name: destinations[index]['name']!,
image: destinations[index]['image']!,
);
},
),
);
}
}
class DestinationCard extends StatelessWidget {
final String name;
final String image;
DestinationCard({required this.name, required this.image});
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Image.network(
image,
height: 200,
fit: BoxFit.cover,
),
Padding(
padding: EdgeInsets.all(10),
child: Text(
name,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
],
),
);
}
}
Step 3: Adding Navigation to Detail Screen
Now, let’s add navigation to a detail screen when a destination is tapped.
lib/main.dart
(continued):
import 'package:flutter/material.dart';
void main() {
runApp(TravelApp());
}
class TravelApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Travel App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
final List<Map<String, String>> destinations = [
{
'name': 'Paris',
'image': 'https://example.com/paris.jpg',
'description': 'The City of Light.',
},
{
'name': 'New York',
'image': 'https://example.com/newyork.jpg',
'description': 'The Big Apple.',
},
{
'name': 'Tokyo',
'image': 'https://example.com/tokyo.jpg',
'description': 'The heart of Japan.',
},
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Travel App'),
),
body: ListView.builder(
itemCount: destinations.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(
name: destinations[index]['name']!,
image: destinations[index]['image']!,
description: destinations[index]['description']!,
),
),
);
},
child: DestinationCard(
name: destinations[index]['name']!,
image: destinations[index]['image']!,
),
);
},
),
);
}
}
class DestinationCard extends StatelessWidget {
final String name;
final String image;
DestinationCard({required this.name, required this.image});
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Image.network(
image,
height: 200,
fit: BoxFit.cover,
),
Padding(
padding: EdgeInsets.all(10),
child: Text(
name,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
],
),
);
}
}
class DetailScreen extends StatelessWidget {
final String name;
final String image;
final String description;
DetailScreen({required this.name, required this.image, required this.description});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(name),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Image.network(
image,
height: 300,
fit: BoxFit.cover,
),
Padding(
padding: EdgeInsets.all(16),
child: Text(
description,
style: TextStyle(fontSize: 18),
),
),
],
),
),
);
}
}
Step 4: Adding Some Styling
To make the app more visually appealing, you can enhance the styling of the components.
lib/main.dart
(continued with styling):
“`dart
import ‘package:flutter/material.dart’;
void main() {
runApp(TravelApp());
}
class TravelApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Travel App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
final List> destinations = [
{
'name': 'Paris',
'image': 'https://example.com/paris.jpg',
'description': 'The City of Light.',
},
{
'name': 'New York',
'image': 'https://example.com/newyork.jpg',
'description': 'The Big Apple.',
},
{
'name': 'Tokyo',
'image': 'https://example.com/tokyo.jpg',
'description': 'The heart of Japan.',
},
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Travel App'),
),
body: ListView.builder(
itemCount: destinations.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(
name: destinations[index]['name']!,
image: destinations[index]['image']!,
description: destinations[index]['description']!,
),
),
);
},
child: DestinationCard(
name: destinations[index]['name']!,
image: destinations[index]['image']!,
),
);
},
),
);
}
}
class DestinationCard extends StatelessWidget {
final String name;
final String image;
DestinationCard({required this.name, required this.image});
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
elevation: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ClipRRect(
borderRadius: BorderRadius.vertical(top: Radius.circular(15)),
child: Image.network(
image,
height: 200,
fit: BoxFit.cover,
),
),
Padding(
padding: EdgeInsets.all(10),
child: Text(
name,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
],
),
);
}
}
class DetailScreen extends StatelessWidget {
final String name;
final String image;
final String description;
DetailScreen({required this.name, required this.image, required this.description});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(name),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Image.network(
image,
height: 300,
fit: BoxFit.cover,
),
Padding(
padding: EdgeInsets.all(16),
child: Text(
description,
style: TextStyle(font
Explanation
- Main Function and App Entry Point: The
main
function runs theTravelApp
widget, which is the root of the app. - MaterialApp: Sets up the app with a title, theme, and home screen.
- HomeScreen: A stateless widget that displays the home screen with a list of destinations in a grid view.
- Destination Model: A simple class representing a travel destination with a name, image URL, and description.
- DestinationCard: A stateless widget to display each destination in a card with an image, name, and description.
- Sample Data: A list of sample destinations with dummy data.
You can expand this example by adding more screens (e.g., details screen, profile screen), navigation, and other features. This code provides a starting point for a travel app with a modern and clean UI using Flutter.