Ahsin Irshad
Senior Flutter Developer | Ex. Native Android Developer
Flutter App Intro/Onboarding Screen with Carousel & Animated Dots — NO Package | Jan, 2024
You’re going to learn how to create an Onboarding page like shows below in your Flutter app.
As you can see the indicators are animated — it’s amazing that it only needs 10 lines of code!
Also created a video tutorial 🎬, Build Flutter App Intro/Onboarding Screen
Get started
Let’s start with OnboardingPage, which is a StatefulWidget. Also, define a variable named _selectedIndex
and set its default value to 0.
class OnboardingPage extends StatefulWidget {
const OnboardingPage({super.key});
@override
State<OnboardingPage> createState() => _OnboardingPageState();
}
class _OnboardingPageState extends State<OnboardingPage> {
int _selctedIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
// TODO: Onboard Content
// TODO: Animated Dots
// TODO: Button
],
),
),
);
}
}
List<Map<String, dynamic>> demoData = [
{
“illustration”: “assets/Illustrations/Illustrations_1.svg”,
“title”: “All your favorites”,
“text”:
“Order from the best local restaurants \nwith easy, on-demand delivery.”,
},
{
“illustration”: “assets/Illustrations/Illustrations_2.svg”,
“title”: “Free delivery offers”,
“text”:
“Free delivery for new customers via Apple Pay\nand others payment methods.”,
},
{
“illustration”: “assets/Illustrations/Illustrations_3.svg”,
“title”: “Choose your food”,
“text”:
“Easily find your type of food craving and\nyou’ll get delivery in wide range.”,
},
];
Onboard Content
In OnboardContent
, we start with an illustration. Following that, there’s a title, which we make larger by setting its style to titleLarge
. Finally, there’s a short description. This is why we have three parameters: illustration
, title
, and text
.
class OnboardContent extends StatelessWidget {
const OnboardContent({
super.key,
required this.illustration,
required this.title,
required this.text,
});
final String illustration, title, text;
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: SvgPicture.asset(illustration),
),
),
const SizedBox(height: 16),
Text(
title,
style: Theme.of(context)
.textTheme
.titleLarge!
.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
text,
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
),
],
);
}
}
Now, let’s put the OnboardContent
into action on our onboarding page. If you look at the preview, you’ll notice that users be able to swipe left or right. We achieve this by using a PageView
. When a page is changed, we update the _selectedIndex
. This will be handy later when we add animated dots to indicate the page position. Replace TODO: Onboard Content
with below code
const Spacer(flex: 2),
SizedBox(
height: 500,
child: PageView.builder(
itemCount: demoData.length,
onPageChanged: (value) {
setState(() {
_selctedIndex = value;
});
},
itemBuilder: (context, index) {
return OnboardContent(
illustration: demoData[index]['illustration'],
title: demoData[index]['title'],
text: demoData[index]['text'],
);
},
),
),
const Spacer(),
Animated dots
When creating animated dots, we opt for Implicit animations because they are straightforward and simple, eliminating the need for controllers or complex configurations. We just need to define the duration. The AnimatedContainer is one of them. Here, if the dot is active, its width expands to 24; otherwise, it remains at 6. The transition from 24 to 6 doesn’t happen instantly; it gradually takes place over the time period specified in the duration.
lass AnimatedDot extends StatelessWidget {
const AnimatedDot({
super.key,
required this.isActive,
});
final bool isActive;
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
height: 6,
width: isActive ? 20 : 6,
decoration: BoxDecoration(
color:
isActive ? primaryColor : const Color(0xFF868686).withOpacity(0.25),
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
);
}
}
Now, to display the dots on our page, simply replace the TODO: Animated Dots
with below code
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(
demoData.length,
(index) => Padding(
padding: const EdgeInsets.only(right: 6),
child: AnimatedDot(isActive: _selctedIndex == index),
),
),
),
const Spacer(flex: 2),
Button
We’re almost there! The only component left to complete is the button. Let’s wrap that up with replace the TODO: Button
with below code
ElevatedButton(
onPressed: () {},
child: Text(
"Get Started".toUpperCase(),
),
),
const Spacer(),
Thank you so much for reading. I hope you found this helpful. If you have any suggestions or feedback, please let me know. Your input is invaluable in helping me create better content for you all.
#Flutter #App #IntroOnboarding #Screen #Carousel #Animated #Dots #Package #Flutter #Jan