Flutter: E-Commerce Product Carousel Page UI with Animation
In this blog, I am going to introduce E-Commerce Product Carousel Page UI . Along with learning the awesome Product Carousel Page UI implementation in Flutter, we will also learn how its coding workflows and structures work.
How to Create a New Future Project
First, we need to create a new Flutter project. For that, make sure that you've installed the Flutter SDK and other Flutter app development-related requirements.
If everything is properly set up, then in order to create a project we can simply run the following command in our desired local directory:
flutter create flutter-product-detail-carousel-ui
After we've set up the project, we can navigate inside the project directory and execute the following command in the terminal to run the project in either an available emulator or an actual device:
flutter run
How to create the Main Chat Screen UI
Now, we are going to start building the UI for our chat application.
First, we need to make some simple configurations to the default boilerplate code in the main.dart file. We'll remove some default code and add the simple MaterialApp
pointing to the remove Container
and Call HomPage page for now:
import 'package:detailpageui/pages/home/home.dart'; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: Home(), ); } }
How to Build the Animation Widgets
Inside the ./lib directory of our root project folder, we need to create a folder called ./widgets. This folder will hold all the dart files for different screens.
Inside ./lib/widgets/ directory, we need to create a file called FadeAnimation.dart. Inside the FadeAnimation.dart file, we need to add the basic Stateless widget code as shown in the code snippet below:
import 'package:flutter/material.dart'; import 'package:simple_animations/simple_animations.dart'; class FadeAnimation extends StatelessWidget { final double delay; final Widget child; const FadeAnimation({super.key, required this.delay, required this.child}); @override Widget build(BuildContext context) { final duration = MultiTrackTween([ Track("opacity").add(Duration(milliseconds: 600), Tween(begin: 0.0, end: 1.0)), Track("translateY").add(Duration(milliseconds: 600), Tween(begin: -25.0, end: 0.0), curve: Curves.easeOut), ]); return ControlledAnimation( delay: Duration(milliseconds: (600 * delay).round()), duration: duration.duration, tween: duration, child: child, builderWithChild: (context, child, animation) => Opacity( opacity: animation["opacity"], child: Transform.translate( offset: Offset( 0, animation["translateY"] ), child: child, ), ), ); } }
for animation to add. simple_animations package here link
installation Command
flutter pub add simple_animations
How to Build the Main Home Screen
Inside the ./lib directory of our root project folder, we need to create a folder called ./pages. This folder will hold all the dart files for different screens.
Inside ./lib/pages/ directory, we need to create a file called ChatPage.dart. Inside the ChatPage.dart file, we need to add the basic Stateful widget code as shown in the code snippet below:
import 'package:detailpageui/widgets/animation/fadeAnimation.dart'; import 'package:flutter/material.dart'; class Home extends StatefulWidget { const Home({super.key}); @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { final List<List<String>> products = [ [ 'assets/images/blazer-1.jpg', 'Dev Hub Blazer One', '100 \$' ], [ 'assets/images/blazer-2.jpeg', 'Dev Hub Blazer Two', '200 \$' ], [ 'assets/images/blazer-3.jpeg', 'Dev Hub Blazer Three', '150 \$' ], [ 'assets/images/blazer-4.jpeg', 'Dev Hub Blazer FOUR', '250 \$' ] ]; int currentIndex = 0; void _next(){ setState(() { if(currentIndex < products.length-1){ currentIndex++; }else{ currentIndex = currentIndex; } }); } void _preve(){ setState(() { if(currentIndex >0 ){ currentIndex--; }else{ currentIndex = 0; } }); } @override Widget build(BuildContext context) { return Scaffold( body: Container( child: Column( children: <Widget>[ GestureDetector( onHorizontalDragEnd: (DragEndDetails details) => { if(details.velocity.pixelsPerSecond.dx < 0){ _next() }else if(details.velocity.pixelsPerSecond.dx > 0){ _preve() } }, child: FadeAnimation(delay: 0.8, child: Container( width: double.infinity, height: 650, decoration: BoxDecoration( image: DecorationImage( image: AssetImage(products[currentIndex][0]), fit: BoxFit.cover ) ), child: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.bottomRight, colors: [ Colors.blueGrey, Colors.grey.withOpacity(.0) ] ) ), child: Column( mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ Container( width: 110, margin: EdgeInsets.only(bottom: 60), child: Row( children: buildIndicator(), ), ) ], ), ), ), ), ), Expanded( child: Transform.translate( offset: Offset(0, -50), child: Container( width: double.infinity, padding: EdgeInsets.all(30), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(30), topRight: Radius.circular(30)) ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ FadeAnimation(delay:1.5, child: Text(products[currentIndex][1], style: TextStyle(color: Colors.blueGrey, fontSize: 40, fontWeight: FontWeight.bold))), SizedBox(height: 10), Row( children: [ FadeAnimation(delay:1.8, child: Text(products[currentIndex][2], style: TextStyle(color: Colors.yellow[700], fontWeight: FontWeight.bold, fontSize: 22),)), SizedBox(width: 10), FadeAnimation(delay:2.2, child: Row( children: [ Icon(Icons.star, size: 18, color: Colors.yellow[700]), Icon(Icons.star, size: 18, color: Colors.yellow[700]), Icon(Icons.star, size: 18, color: Colors.yellow[700]), Icon(Icons.star, size: 18, color: Colors.yellow[700]), Icon(Icons.star_half, size: 18, color: Colors.yellow[700]), SizedBox(width: 10), Text("4.5/80 reviews", style: TextStyle(color: Colors.blueGrey, fontSize: 14)) ], )) ], ), Expanded( child: Align( alignment: Alignment.bottomCenter, child: Container( height: 50, decoration: BoxDecoration( color: Colors.yellow[800], borderRadius: BorderRadius.circular(10) ), child: Center( child: FadeAnimation(delay:2.5, child: Text("Add to Cart", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),)), ), ), ), ) ], ), ), ), ) ], ), ), ); } Widget _indicator(bool isActive){ return Expanded( child: Container( height: 5, margin: EdgeInsets.only(right: 5), decoration: BoxDecoration( borderRadius: BorderRadius.circular(50), color: isActive ? Colors.blueGrey: Colors.white ), ) ); } List<Widget> buildIndicator(){ List<Widget> indicator = []; for(int i =0; i< products.length; i++){ if(currentIndex == i){ indicator.add(_indicator(true)); }else{ indicator.add(_indicator(false)); } } return indicator; } }