Reputation: 487
I would like to implement in Flutter a Staggered Grid view - such as the Pinterest staggered grid view (which used to be implemented via their own Android Widget, and now via the Google's StaggeredGridLayoutManager).
So the requirements are:
I know there is a plugin which is named flutter_staggered_grid_view, but this is of no use because it requires to know in advance the precise height of each tile of the grid - which of course it is not my case.
Upvotes: 21
Views: 43938
Reputation: 396
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view.dart';
class HomePage extends StatelessWidget {
final List<String> images = [
"https://uae.microless.com/cdn/no_image.jpg",
"https://images-na.ssl-images-amazon.com/images/I/81aF3Ob-2KL._UX679_.jpg",
"https://www.boostmobile.com/content/dam/boostmobile/en/products/phones/apple/iphone-7/silver/device-front.png.transform/pdpCarousel/image.jpg",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSgUgs8_kmuhScsx-J01d8fA1mhlCR5-1jyvMYxqCB8h3LCqcgl9Q",
"https://ae01.alicdn.com/kf/HTB11tA5aiAKL1JjSZFoq6ygCFXaw/Unlocked-Samsung-GALAXY-S2-I9100-Mobile-Phone-Android-Wi-Fi-GPS-8-0MP-camera-Core-4.jpg_640x640.jpg",
"https://media.ed.edmunds-media.com/gmc/sierra-3500hd/2018/td/2018_gmc_sierra-3500hd_f34_td_411183_1600.jpg",
"https://hips.hearstapps.com/amv-prod-cad-assets.s3.amazonaws.com/images/16q1/665019/2016-chevrolet-silverado-2500hd-high-country-diesel-test-review-car-and-driver-photo-665520-s-original.jpg",
"https://www.galeanasvandykedodge.net/assets/stock/ColorMatched_01/White/640/cc_2018DOV170002_01_640/cc_2018DOV170002_01_640_PSC.jpg",
"https://media.onthemarket.com/properties/6191869/797156548/composite.jpg",
"https://media.onthemarket.com/properties/6191840/797152761/composite.jpg",
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
leading: Icon(
Icons.arrow_back_ios,
color: Colors.black,
),
actions: [
IconButton(
onPressed: () {},
icon: Icon(
Icons.shopping_cart,
color: Colors.black,
),
)
],
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: Text(
"ShopX",
style: TextStyle(
fontFamily: 'avenir',
fontSize: 32,
fontWeight: FontWeight.w900,
),
),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.view_list_rounded),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.grid_view),
),
],
),
),
Expanded(
child: StaggeredGridView.countBuilder(
crossAxisCount: 2,
itemCount: images.length,
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
itemBuilder: (context, index) {
return Container(
child: Card(
child: Column(
children: [
Image.network(images[index]),
Text("Some Text"),
],
),
),
);
},
staggeredTileBuilder: (index) => StaggeredTile.fit(1),
),
),
],
),
);
}
Upvotes: 2
Reputation: 22437
As Romain Rastler said, StaggeredGridView
is great solution and he is updating it regularly, below is an example, I have built to get different height grid view when we are fetching content from internet(you can apply to a API):
First of all add this dependency (currently its version is 0.3.0
)
pubspec.yaml : flutter_staggered_grid_view: 0.3.0
then import this : import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
class StaggeredGridExample extends StatefulWidget {
@override
_StaggeredGridExampleState createState() => _StaggeredGridExampleState();
}
class _StaggeredGridExampleState extends State<StaggeredGridExample> {
final List<String> images = [
"https://uae.microless.com/cdn/no_image.jpg",
"https://images-na.ssl-images-amazon.com/images/I/81aF3Ob-2KL._UX679_.jpg",
"https://www.boostmobile.com/content/dam/boostmobile/en/products/phones/apple/iphone-7/silver/device-front.png.transform/pdpCarousel/image.jpg",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSgUgs8_kmuhScsx-J01d8fA1mhlCR5-1jyvMYxqCB8h3LCqcgl9Q",
"https://ae01.alicdn.com/kf/HTB11tA5aiAKL1JjSZFoq6ygCFXaw/Unlocked-Samsung-GALAXY-S2-I9100-Mobile-Phone-Android-Wi-Fi-GPS-8-0MP-camera-Core-4.jpg_640x640.jpg",
"https://media.ed.edmunds-media.com/gmc/sierra-3500hd/2018/td/2018_gmc_sierra-3500hd_f34_td_411183_1600.jpg",
"https://hips.hearstapps.com/amv-prod-cad-assets.s3.amazonaws.com/images/16q1/665019/2016-chevrolet-silverado-2500hd-high-country-diesel-test-review-car-and-driver-photo-665520-s-original.jpg",
"https://www.galeanasvandykedodge.net/assets/stock/ColorMatched_01/White/640/cc_2018DOV170002_01_640/cc_2018DOV170002_01_640_PSC.jpg",
"https://media.onthemarket.com/properties/6191869/797156548/composite.jpg",
"https://media.onthemarket.com/properties/6191840/797152761/composite.jpg",
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: StaggeredGridView.countBuilder(
crossAxisCount: 4,
itemCount: images.length,
itemBuilder: (BuildContext context, int index) => Card(
child: Column(
children: <Widget>[
Image.network(images[index]),
Text("Some text"),
],
),
),
staggeredTileBuilder: (int index) =>
new StaggeredTile.fit(2),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
),
);
}
}
Upvotes: 13
Reputation: 13431
Try this.
return new StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection(PRODUCTS_COLLECTION).snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Center(child: new CircularProgressIndicator());
return new StaggeredGridView.count(
physics: new BouncingScrollPhysics(),
crossAxisCount: 2,
children: buildGrid(snapshot.data.documents),
staggeredTiles: generateRandomTiles(snapshot.data.documents.length),
);
},
);
List<Widget> buildGrid(List<DocumentSnapshot> documents) {
List<Widget> _gridItems = [];
_products.clear();
for (DocumentSnapshot document in documents) {
_products.add(Product.fromDocument(document));
}
for (Product product in _products) {
_gridItems.add(buildGridItem(product));
}
return _gridItems;
}
Widget buildGridItem(Product product) {
return new GestureDetector(
child: new Card(
elevation: 2.0,
margin: const EdgeInsets.all(5.0),
child: new Stack(
alignment: Alignment.center,
children: <Widget>[
new Hero(
tag: product.name,
child: new Image.network(product.imageUrl, fit: BoxFit.cover),
),
new Align(
child: new Container(
padding: const EdgeInsets.all(6.0),
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text('\u20B9 ${product.price}',
style: new TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16.0)),
new Text(product.name,
style: new TextStyle(color: Colors.white)),
],
),
color: Colors.black.withOpacity(0.4),
width: double.infinity,
),
alignment: Alignment.bottomCenter,
),
],
),
),
onTap: () async {
// TODO
},
);
}
List<StaggeredTile> generateRandomTiles(int count) {
Random rnd = new Random();
List<StaggeredTile> _staggeredTiles = [];
for (int i=0; i<count; i++) {
num mainAxisCellCount = 0;
double temp = rnd.nextDouble();
if (temp > 0.6) {
mainAxisCellCount = temp + 0.5;
} else if (temp < 0.3) {
mainAxisCellCount = temp + 0.9;
} else {
mainAxisCellCount = temp + 0.7;
}
_staggeredTiles.add(new StaggeredTile.count(rnd.nextInt(1) + 1, mainAxisCellCount));
}
return _staggeredTiles;
}
Upvotes: 3
Reputation: 5612
I've updated the flutter_staggered_grid_view package.
Now you can add tiles that fit their content size like this:
You have to create tiles using the StaggeredTile.fit(this.crossAxisCellCount)
constructor to do it.
Hope it helps.
Upvotes: 34