INTRODUCTION
In the ever-evolving world of mobile and web development, a visually appealing and functional landing page plays a pivotal role in capturing user attention. Flutter, Google’s UI toolkit, empowers developers to create versatile and responsive landing pages that seamlessly adapt to various platforms. This blog will guide you through the process of building a dynamic landing page using Flutter, focusing on creating an attractive Landing page for a Music Streaming app.
WHY DO WE NEED TO DO
- First Impressions Matter: A landing page is often the first interaction users have with your application.
- Highlight Features: It showcases the app’s core offerings and user benefits.
- Drive Engagement: A well-designed landing page can convert visitors into users by clearly communicating your value proposition.
- Cross-Platform Compatibility: With Flutter, you can ensure your landing page looks consistent on Android, iOS, and the web.
How to set up the project:
To build our versatile landing page, we’ll leverage the following tools and technologies:
- Flutter SDK: For creating natively compiled applications.
- Dart: Flutter’s programming language.
- Visual Studio Code or Android Studio: Development environment.
- Pub.dev Packages: Such as provider for state management, google_fonts for custom typography, and flutter_svg for scalable vector graphics.
HOW DO WE SOLVE THIS
Flutter’s widget-based architecture allows for:
- Reusable Components: Create modular, maintainable, and reusable widgets for efficiency.
- Customizable UI: Tailor layouts to match brand identity using Flutter’s flexible widgets and theming options.
- Cross-Platform Development: Save time and effort by building a single landing page that runs on multiple platforms.
Install Flutter SDK: Download the latest version of Flutter from the official website.
- Configure an Editor: Use Visual Studio Code or Android Studio with Flutter and Dart plugins installed.
- Set Up a Device: Use an emulator, simulator, or physical device for testing.
- Run the App: Verify the setup by running flutter doctor and executing the default app with flutter run.
Steps to setup the environment:
- Step 1: Create a screens folder inside the lib folder
- Step 2: Create a file inside the screen folder and name it as ‘dashboard.dart’ or ‘landing.dart’ as per your need.
- Step 3: Import material.dart for different UI styles and colors.
- Step 4: Write the following code and run the command ‘flutter run’.
import ‘dart:async’;
import ‘package:doyensys_leave_management/Screens/approval-grid.dart’;
import ‘package:doyensys_leave_management/Screens/bottom-navigation.dart’;
import ‘package:doyensys_leave_management/Screens/bulk-leave-approval.dart’;
import ‘package:doyensys_leave_management/Screens/holidayslist.dart’;
import ‘package:doyensys_leave_management/Screens/leave-approval.dart’;
import ‘package:doyensys_leave_management/Screens/leave-availabilty.dart’;
import ‘package:doyensys_leave_management/Screens/leave-history.dart’;
import ‘package:doyensys_leave_management/Screens/leave-request.dart’;
import ‘package:doyensys_leave_management/Screens/pending-leave-approval.dart’;
import ‘package:doyensys_leave_management/Screens/userprofile.dart’;
import ‘package:flutter/material.dart’;
void main() => runApp(MaterialApp(home: DashboardPage(userName: ”,)));
class DashboardApp extends StatelessWidget {
final String userName;
DashboardApp({required this.userName});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
useMaterial3: true, // Enable Material 3 for modern styling
),
home: DashboardPage(userName: userName),
);
}
}
class DashboardPage extends StatefulWidget {
final String userName;
DashboardPage({required this.userName});
@override
_DashboardPageState createState() => _DashboardPageState();
}
class _DashboardPageState extends State<DashboardPage> {
final List<Map<String, String>> quotes = [
{‘quote’: “I choose a lazy person to do a hard job.Coz,a lazy person will find an easy way to do it.”, ‘author’: ‘Bill Gates’},
{‘quote’: “Monday is proof that we survived the weekend, but barely.”, ‘author’: ‘Anonymous’},
{‘quote’: “Doing nothing is very hard to do. You never know when you’re finished.”, ‘author’: ‘Leslie Nielsen’},
{‘quote’: “I love deadlines. I love the whooshing noise they make as they go by.”, ‘author’: ‘Douglas Adams’},
{‘quote’: “I always arrive late at the office, but I make up for it by leaving early.”, ‘author’: ‘Charles Lamb’},
{‘quote’: “Music can change the world because it can change people.”, ‘author’: ‘Bono’},
];
int currentQuoteIndex = 0;
int _selectedIndex = 0;
late Timer _timer;
late PageController _pageController;
@override
void initState() {
super.initState();
_pageController = PageController();
_timer = Timer.periodic(Duration(seconds: 4), (timer) {
setState(() {
currentQuoteIndex = (currentQuoteIndex + 1) % quotes.length;
_pageController.animateToPage(currentQuoteIndex,
duration: Duration(milliseconds: 300), curve: Curves.easeInOut);
});
});
}
@override
void dispose() {
_timer.cancel();
_pageController.dispose();
super.dispose();
}
void _onBottomNavTap(int index) {
setState(() {
_selectedIndex = index;
});
// Navigate to the corresponding screen based on the tapped index
switch (index) {
case 1:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LeaveHistoryPage()),
);
break;
case 2:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LeaveRequestScreen()),
);
break;
case 3:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => UserProfileScreen()),
);
break;
}
}
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
final isPortrait = MediaQuery.of(context).orientation == Orientation.portrait;
return Scaffold(
appBar: AppBar(
title: const Text(‘Home’, style: TextStyle(
fontSize: 18, // Reduce the size here
fontWeight: FontWeight.w700,
),),
backgroundColor: Colors.deepPurple.shade300,
foregroundColor: Colors.white,
elevation: 0,
),
body: Padding(
padding: EdgeInsets.all(screenWidth * 0.04), // Responsive padding
child: Column(
children: <Widget>[
// Welcome message
Padding(
padding: EdgeInsets.only(bottom: screenHeight * 0.002),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
‘${getGreeting()}, ${widget.userName}!’,
style: TextStyle(fontSize: screenWidth*0.05, fontWeight:FontWeight.bold ),
),
SizedBox(width: 4), // Adds space between text and icon
Icon(
Icons.sentiment_satisfied_alt,
color: Colors.deepPurple.shade300, // Set the color of the icon
size: 26, // Set the size of the icon
),
],
),
),
// Quote sec
Padding(
padding: EdgeInsets.symmetric(vertical: screenHeight * 0.002),
child: Column(
children: [
Text(
‘”${quotes[currentQuoteIndex][‘quote’]}“‘,
style: TextStyle(
fontSize: screenWidth * 0.040,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w600,
color: Colors.blueGrey,
),
textAlign: TextAlign.center,
),
SizedBox(height: screenHeight * 0.01),
Text(
‘- ${quotes[currentQuoteIndex][‘author’]}‘,
style: TextStyle(
fontSize: screenWidth * 0.04,
fontWeight: FontWeight.w500,
color: Colors.blueGrey,
),
textAlign: TextAlign.center,
),
],
),
),
// Grid with cards
Expanded(
child: GridView.count(
crossAxisCount: isPortrait ? 2 : 3, // Adaptive columns
crossAxisSpacing: screenWidth * 0.02, //hor spacing
mainAxisSpacing: screenHeight * 0.01, //vertical spacing
childAspectRatio: isPortrait ? 1.05 : 1.05, // Adaptive aspect ratio
children: <Widget>[
DashboardCard(
title: ‘Trending’,
icon: Icons.whatshot,
gradientColors: [Colors.deepPurple.shade300, Colors.deepPurple.shade600],
textColor: Colors.white,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LeaveRequestScreen()));
},
),
DashboardCard(
title: ‘Your Playlist’,
icon: Icons.queue_music ,
gradientColors: [Colors.deepPurple.shade300, Colors.deepPurple.shade600],
// gradientColors: [Colors.red.shade700, Colors.red.shade900],
textColor: Colors.white,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HolidayListScreen()));
},
),
DashboardCard(
title: ‘Premium Subscription’,
icon: Icons.monetization_on,
gradientColors: [Colors.deepPurple.shade300, Colors.deepPurple.shade600],
// gradientColors: [Colors.red.shade700, Colors.red.shade900],
textColor: Colors.white,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ApprovalGridPage()));
},
),
DashboardCard(
title: ‘Recently Played’,
icon: Icons.send_time_extension,
gradientColors: [Colors.deepPurple.shade300, Colors.deepPurple.shade600],
// gradientColors: [Colors.red.shade700, Colors.red.shade900],
textColor: Colors.white,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LeaveAvailabilityScreen()));
},
),
],
),
),
SizedBox(height: screenHeight * 0.025),
// Carousel
Container(
height: screenHeight * 0.20,
child: PageView(
controller: _pageController,
children: [
QuoteCard(
imageUrl: ‘https://images.pexels.com/photos/323933/pexels-photo-323933.jpeg?auto=compress&cs=tinysrgb&w=600‘,
quote: “The only limit to our realization of tomorrow is our doubts of today.”,
author: “Franklin D. Roosevelt”,
),
QuoteCard(
imageUrl: ‘https://images.pexels.com/photos/207700/pexels-photo-207700.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2‘,
quote: “Life is what happens when you’re busy making other plans.”,
author: “John Lennon”,
),
QuoteCard(
imageUrl: ‘https://images.pexels.com/photos/9352/glass-time-watch-business.jpg?auto=compress&cs=tinysrgb&w=600‘,
quote: “The best way to predict your future is to create it.”,
author: “Peter Drucker”,
),
QuoteCard(
imageUrl: ‘https://images.pexels.com/photos/167259/pexels-photo-167259.jpeg?auto=compress&cs=tinysrgb&w=600‘,
quote: “The journey of a thousand miles begins with a single step.”,
author: “Lao Tzu”,
),
QuoteCard(
quote: “Where words fail, music speaks.”,
author: “Hans Christian Andersen”,
),
],
),
),
],
),
),
// bottomNavigationBar: BottomNavBar(),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.white,
selectedItemColor: const Color.fromARGB(205, 172, 83, 250),
unselectedItemColor: const Color.fromARGB(179, 163, 163, 163),
currentIndex: _selectedIndex,
selectedLabelStyle: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14
),
unselectedLabelStyle: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 12
),
onTap: _onBottomNavTap,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: ‘Home’,
),
BottomNavigationBarItem(
icon: Icon(Icons.access_time_filled),
label: ‘History’,
),
BottomNavigationBarItem(
icon: Icon(Icons.favorite),
label: ‘Favorites’,
),
BottomNavigationBarItem(
icon: Icon(Icons.person_pin),
label: ‘Profile’,
),
],
),
);
}
String getGreeting() {
final hour = DateTime.now().hour;
if (hour < 12) {
return ‘Good Morning’;
} else if (hour < 17) {
return ‘Good Afternoon’;
} else {
return ‘Good Evening’;
}
}
}
// Rest of the widgets remain unchanged
// Custom DashboardCard widget
class DashboardCard extends StatelessWidget {
final String title;
final IconData icon;
final List<Color> gradientColors;
final Color textColor;
final VoidCallback onTap;
final double fontSize;
DashboardCard({
required this.title,
required this.icon,
required this.gradientColors,
required this.textColor,
required this.onTap,
this.fontSize =14 });
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: gradientColors,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(12),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircleAvatar(
backgroundColor: Colors.white.withOpacity(0.3),
radius: 34,
child: Icon(
icon,
color: textColor,
size: 32,
),
),
SizedBox(height: 12),
Text(
title,
style: TextStyle(
color: textColor,
fontSize: 16,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
],
),
),
);
}
}
// Custom QuoteCard widget
class QuoteCard extends StatelessWidget {
final String imageUrl;
final String quote;
final String author;
const QuoteCard({
Key? key,
required this.imageUrl,
required this.quote,
required this.author,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(imageUrl),
fit: BoxFit.cover,
),
borderRadius: BorderRadius.circular(15.0),
),
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
quote,
style: const TextStyle(
fontSize: 16,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold,
color: Colors.white,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
Text(
‘- $author‘,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white,
),
textAlign: TextAlign.center,
),
],
),
);
}
}
The User Interface
CONCLUSION
Flutter’s flexibility and widget-based approach make it an ideal choice for building versatile landing pages. By combining modular design, reusable components, and cross-platform compatibility, you can deliver an engaging user experience. Start crafting your landing page today and unlock the potential of Flutter!