Flutter Stacked Item ListView | Scroll Animation
Last updated Feb 02, 2021Hello Guys, In this post we are going to cover create a stacked Listview Items with Aniimations.
This will give the good animation on scrolling the list items from top to bottom and viceversa
For making this animations we have used
By doing this you learn controll the listview in new way.
For this example we are showing the list of restaurants with their image,address...
Let's get started
Step 1: Create a Flutter project
Step 2: Create a Data class which contains the Restaurant details
The constants.dart file contains below data
const RESTAURANTS = [
{
"name":"Home Cravings",
"brand":"Healthy Food",
"location":"Miyapur, Hyderabad",
"image":"https://b.zmtcdn.com/data/pictures/chains/9/19360109/e413ff9d1ca752e291a0f97a739873d5_featured_v2.jpg?output-format=webp"
},{
"name":"Shahi Schezwan",
"brand":"North Indian",
"location":"Hitech City, Hyderabad",
"image":"https://b.zmtcdn.com/data/pictures/chains/6/19336726/e1b8d3814aca73d501d2a40bde81991d_featured_v2.jpg?output-format=webp"
},
{
"name":"Healthy Shakes",
"brand":"Beverages, Fast Food",
"location":"Gachibowli, Hyderabad",
"image":"https://b.zmtcdn.com/data/pictures/chains/5/19035705/e2db91bfb71093002ad4b179e4908cf8_featured_v2.jpeg?output-format=webp"
},
{
"name":"PourHouse7",
"brand":"Casual Dining, Bar - North Indian",
"location":"Gachibowli",
"image":"https://b.zmtcdn.com/data/pictures/4/18661594/0a37f7f12faf9295afce797564790182.jpg?output-format=webp&fit=around|771.75:416.25&crop=771.75:416.25;*,*"
},
{
"name":"Bistro Milano",
"brand":"Casual Dining - Continental,",
"location":"Jubilee Hills, Hyderabad",
"image":"https://b.zmtcdn.com/data/pictures/4/19331884/ab1dd2a50883329db53c1f7c1248c80a.jpg?output-format=webp&fit=around|771.75:416.25&crop=771.75:416.25;*,*"
},
{
"name":"Drunkyard",
"brand":"Casual Dining, Bar ",
"location":"Gachibowli",
"image":"https://b.zmtcdn.com/data/pictures/5/18265585/8f613fae7df645e4771ca774d33047f2_featured_v2.jpg?output-format=webp"
}
,{
"name":"Shahi Schezwan",
"brand":"North Indian",
"location":"Hitech City, Hyderabad",
"image":"https://b.zmtcdn.com/data/pictures/chains/6/19336726/e1b8d3814aca73d501d2a40bde81991d_featured_v2.jpg?output-format=webp"
},
{
"name":"Healthy Shakes",
"brand":"Beverages, Fast Food",
"location":"Gachibowli, Hyderabad",
"image":"https://b.zmtcdn.com/data/pictures/chains/5/19035705/e2db91bfb71093002ad4b179e4908cf8_featured_v2.jpeg?output-format=webp"
},
{
"name":"PourHouse7",
"brand":"Casual Dining, Bar - North Indian",
"location":"Gachibowli",
"image":"https://b.zmtcdn.com/data/pictures/4/18661594/0a37f7f12faf9295afce797564790182.jpg?output-format=webp&fit=around|771.75:416.25&crop=771.75:416.25;*,*"
}
];
|
Step 3: Update main.dart file
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final CategoriesScroller categoriesScroller = CategoriesScroller();
ScrollController controller = ScrollController();
bool closeTopContainer = false;
double topContainer = 0;
List<Widget> itemsData = [];
void getPostsData() {
List<dynamic> responseList = RESTAURANTS;
List<Widget> listItems = [];
responseList.forEach((post) {
listItems.add(Container(
height: 150,
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(20.0)), color: Colors.white, boxShadow: [
BoxShadow(color: Colors.black.withAlpha(100), blurRadius: 10.0),
]),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
post["name"],
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Container(
width: 100,
child: Text(
post["brand"],
style: const TextStyle(fontSize: 17, color: Colors.grey),
),
),
SizedBox(
height: 10,
),
Text(
" ${post["location"]}",
style: const TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.bold),
)
],
),
Image.network(
"${post["image"]}",
height: 100,
width: 100,
)
],
),
)));
});
setState(() {
itemsData = listItems;
});
}
@override
void initState() {
super.initState();
getPostsData();
controller.addListener(() {
double value = controller.offset/119;
setState(() {
topContainer = value;
closeTopContainer = controller.offset > 50;
});
});
}
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
final double categoryHeight = size.height*0.30;
return SafeArea(
child: Scaffold(
backgroundColor: Colors.blueGrey,
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.pinkAccent,
leading: Icon(
Icons.menu,
color: Colors.white,
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search, color: Colors.white),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.person, color: Colors.white),
onPressed: () {},
)
],
),
body: Container(
height: size.height,
margin: EdgeInsets.only(top: 10),
child: Column(
children: <Widget>[
Card(
color: Colors.lightGreen,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text(
"Popular Restaurants",
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20),
),
Text(
"Menu",
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20),
),
],
),
),
),
const SizedBox(
height: 10,
),
AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: closeTopContainer?0:1,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
width: size.width,
alignment: Alignment.topCenter,
height: closeTopContainer?0:categoryHeight,
child: categoriesScroller),
),
Expanded(
child: ListView.builder(
controller: controller,
itemCount: itemsData.length,
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) {
double scale = 1.0;
if (topContainer > 0.5) {
scale = index + 0.5 - topContainer;
if (scale < 0) {
scale = 0;
} else if (scale > 1) {
scale = 1;
}
}
return Opacity(
opacity: scale,
child: Transform(
transform: Matrix4.identity()..scale(scale,scale),
alignment: Alignment.bottomCenter,
child: Align(
heightFactor: 0.7,
alignment: Alignment.topCenter,
child: itemsData[index]),
),
);
})),
],
),
),
),
);
}
}
class CategoriesScroller extends StatelessWidget {
const CategoriesScroller();
@override
Widget build(BuildContext context) {
final double categoryHeight = MediaQuery.of(context).size.height * 0.30 - 50;
return SingleChildScrollView(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
child: FittedBox(
fit: BoxFit.fill,
alignment: Alignment.topCenter,
child: Row(
children: <Widget>[
Container(
width: 150,
margin: EdgeInsets.only(right: 20),
height: categoryHeight,
child: Card(
elevation: 10,
borderOnForeground: true,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Stack(
children: [
Image.network("https://b.zmtcdn.com/data/pictures/chains/6/19336726/e1b8d3814aca73d501d2a40bde81991d_featured_v2.jpg",width: 150,height: 150,),
Positioned(
top: 0,
left: 10,
child: Text(
"Famous",
style: TextStyle(fontSize: 20, color: Colors.red, fontWeight: FontWeight.bold),
),),
Positioned(
bottom: 0,
left: 10,
child: Text(
"20 Items",
style: TextStyle(fontSize: 16, color: Colors.red),
),),
],
),
),
),
),
Container(
width: 150,
margin: EdgeInsets.only(right: 20),
height: categoryHeight,
child: Card(
elevation: 10,
borderOnForeground: true,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Stack(
children: [
Image.network("https://b.zmtcdn.com/data/pictures/4/18661594/0a37f7f12faf9295afce797564790182.jpg?output-format=webp&fit=around|771.75:416.25&crop=771.75:416.25;*,*",width: 150,height: 150,),
Positioned(
top: 0,
left: 10,
child: Text(
"Newest",
style: TextStyle(fontSize: 20, color: Colors.green, fontWeight: FontWeight.bold),
),),
Positioned(
bottom: 0,
left: 10,
child: Text(
"20 Items",
style: TextStyle(fontSize: 16, color: Colors.green),
),),
],
),
),
),
),
Container(
width: 150,
margin: EdgeInsets.only(right: 20),
height: categoryHeight,
child: Card(
elevation: 10,
borderOnForeground: true,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Stack(
children: [
Image.network("https://b.zmtcdn.com/data/pictures/5/18265585/8f613fae7df645e4771ca774d33047f2_featured_v2.jpg?output-format=webp",width: 150,height: 150,fit: BoxFit.fill,),
Positioned(
top: 0,
left: 10,
child: Text(
"DrunkYard",
style: TextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold),
),),
Positioned(
bottom: 0,
left: 10,
child: Text(
"20 Items",
style: TextStyle(fontSize: 16, color: Colors.white),
),),
],
),
),
),
),
Container(
width: 150,
margin: EdgeInsets.only(right: 20),
height: categoryHeight,
child: Card(
elevation: 10,
borderOnForeground: true,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Stack(
children: [
Image.network("https://b.zmtcdn.com/data/pictures/chains/6/19336726/e1b8d3814aca73d501d2a40bde81991d_featured_v2.jpg",width: 150,height: 150,),
Positioned(
top: 0,
left: 10,
child: Text(
"Newest",
style: TextStyle(fontSize: 20, color: Colors.green, fontWeight: FontWeight.bold),
),),
Positioned(
bottom: 0,
left: 10,
child: Text(
"20 Items",
style: TextStyle(fontSize: 16, color: Colors.green),
),),
],
),
),
),
),
],
),
),
),
);
}
}
|
Step 4: Run the application
Article Contributed By :
|
|
|
|
4883 Views |