In this flutter tutorial, we will create Flutter Onboarding Screen using Flutter Liquid Swipe animation. The onboarding screen is a list of pages we use to explain the basics of an app. It only appears for the first time. So, to create an onboarding screen in Flutter, we will follow the steps below.
- Design the Flutter Onboarding UI with the help of Flutter Liquid Swipe and Smooth Page Indicator Packages.
- Add Logic using Flutter Stateful widgets
- Separate Logic and Design using GetX State Management.
Worthwhile Links
- Install Android Studio
- Install Flutter
- Create a new flutter app
- Create Folder Structure
- Setup Theme in Flutter for Light & Dark Mode
This is the tutorial of our Flutter Login App Series.
Watch Youtube tutorial
class OnBoardingScreen extends StatelessWidget {
const OnBoardingScreen({Key? key}) : super(key: key);@override
Widget build(BuildContext context) {
final obController = OnBoardingController();
return Scaffold(
body: Stack(
alignment: Alignment.center,
children: [
LiquidSwipe(
pages: obController.pages,
enableSideReveal: true,
liquidController: obController.controller,
onPageChangeCallback: obController.onPageChangedCallback,
slideIconWidget: const Icon(Icons.arrow_back_ios),
waveType: WaveType.circularReveal,
),
Positioned(
bottom: 60.0,
child: OutlinedButton(
onPressed: () => obController.animateToNextSlide(),
style: ElevatedButton.styleFrom(
side: const BorderSide(color: Colors.black26),
shape: const CircleBorder(),
padding: const EdgeInsets.all(20),
onPrimary: Colors.white,
),
child: Container(
padding: const EdgeInsets.all(20.0),
decoration: const BoxDecoration(
color: tDarkColor, shape: BoxShape.circle),
child: const Icon(Icons.arrow_forward_ios),
),
),
),
Positioned(
top: 50,
right: 20,
child: TextButton(
onPressed: () => obController.skip(),
child: const Text("Skip", style: TextStyle(color: Colors.grey)),
),
),
Obx(
() => Positioned(
bottom: 10,
child: AnimatedSmoothIndicator(
count: 3,
activeIndex: obController.currentPage.value,
effect: const ExpandingDotsEffect(
activeDotColor: Color(0xff272727),
),
),
),
),
],
),
);
}}
class OnBoardingController extends GetxController{final controller = LiquidController();
RxInt currentPage = 0.obs;final pages = [
OnBoardingPageWidget(
model: OnBoardingModel(
image: tOnBoardingImage1,
title: tOnBoardingTitle1,
subTitle: tOnBoardingSubTitle1,
counterText: tOnBoardingCounter1,
bgColor: tOnBoardingPage1Color,
),
),
OnBoardingPageWidget(
model: OnBoardingModel(
image: tOnBoardingImage2,
title: tOnBoardingTitle2,
subTitle: tOnBoardingSubTitle2,
counterText: tOnBoardingCounter2,
bgColor: tOnBoardingPage2Color,
),
),
OnBoardingPageWidget(
model: OnBoardingModel(
image: tOnBoardingImage3,
title: tOnBoardingTitle3,
subTitle: tOnBoardingSubTitle3,
counterText: tOnBoardingCounter3,
bgColor: tOnBoardingPage3Color,
),
),
];skip() => controller.jumpToPage(page: 2);
animateToNextSlide() {
int nextPage = controller.currentPage + 1;
controller.animateToPage(page: nextPage);
}
onPageChangedCallback(int activePageIndex) => currentPage.value = activePageIndex;
}
class OnBoardingPageWidget extends StatelessWidget {
const OnBoardingPageWidget({
Key? key,
required this.model,
}) : super(key: key);final OnBoardingModel model;
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Container(
padding: const EdgeInsets.all(tDefaultSize),
color: model.bgColor,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image(
image: AssetImage(model.image),
height: size.height * 0.45,
),
Column(
children: [
Text(
model.title,
style: Theme.of(context).textTheme.headline3,
),
Text(
model.subTitle,
textAlign: TextAlign.center,
),
],
),
Text(
model.counterText,
style: Theme.of(context).textTheme.headline6,
),
const SizedBox(
height: 80.0,
)
],
),
);
}
}