Skip to content

Instantly share code, notes, and snippets.

@bizz84
Created January 12, 2023 10:42
Show Gist options
  • Save bizz84/94612fce6daf6e689d8caced1ba30685 to your computer and use it in GitHub Desktop.
Save bizz84/94612fce6daf6e689d8caced1ba30685 to your computer and use it in GitHub Desktop.
SliverAlignedGrid bottom overflow bug when loading a CachedNetworkImage
// Note: this example needs the flutter_staggered_grid_view and cached_network_image packages to run correctly.
import 'dart:math';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.indigo,
),
home: const ProductsGridScreen(),
);
}
}
class ProductsGridScreen extends StatefulWidget {
const ProductsGridScreen({super.key, this.onPressed});
final void Function(BuildContext, String)? onPressed;
@override
State<ProductsGridScreen> createState() => _ProductsGridScreenState();
}
class _ProductsGridScreenState extends State<ProductsGridScreen> {
int _productsToShow = 1;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('SliverAlignedGrid bug'),
actions: [
TextButton(
onPressed: () => setState(() => _productsToShow = 1),
child: const Text(
'Reset',
style: TextStyle(color: Colors.white),
),
//label: const Text('Reset')),
),
],
),
body: CustomScrollView(
slivers: [
ProductsSliverAlignedGrid(
itemCount: min(_productsToShow, kTestProducts.length),
itemBuilder: (_, index) {
final product = kTestProducts[index];
return ProductCard(product: product);
},
),
],
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () => setState(() => ++_productsToShow),
),
);
}
}
/// Used to show a single product inside a card.
class ProductCard extends StatelessWidget {
const ProductCard({super.key, required this.product, this.onPressed});
final Product product;
final VoidCallback? onPressed;
// * Keys for testing using find.byKey()
static const productCardKey = Key('product-card');
@override
Widget build(BuildContext context) {
return Card(
child: InkWell(
key: productCardKey,
onTap: onPressed,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
CachedNetworkImage(imageUrl: product.imageUrl),
// Note: wrapping this with `AspectRatio` prevents the layout jump
// and always renders correctly
// AspectRatio(
// aspectRatio: 1,
// child: CachedNetworkImage(imageUrl: product.imageUrl),
// ),
const SizedBox(height: 8),
const Divider(),
const SizedBox(height: 8),
Text(product.title, style: Theme.of(context).textTheme.headline6),
const SizedBox(height: 24),
Text('\$${product.price}',
style: Theme.of(context).textTheme.headline5),
const SizedBox(height: 4),
Text(
product.availableQuantity <= 0
? 'Out of Stock'
: 'Quantity: ${product.availableQuantity}',
style: Theme.of(context).textTheme.caption,
)
],
),
),
),
);
}
}
class ProductsSliverAlignedGrid extends StatelessWidget {
const ProductsSliverAlignedGrid({
super.key,
required this.itemCount,
required this.itemBuilder,
});
/// Total number of items to display.
final int itemCount;
/// Function used to build a widget for a given index in the grid.
final Widget Function(BuildContext, int) itemBuilder;
@override
Widget build(BuildContext context) {
return SliverPadding(
padding: const EdgeInsets.all(16),
sliver: SliverAlignedGrid.count(
crossAxisCount: 3,
mainAxisSpacing: 24,
crossAxisSpacing: 24,
itemBuilder: itemBuilder,
itemCount: itemCount,
),
);
}
}
/// Class representing a product.
class Product {
const Product({
required this.id,
required this.imageUrl,
required this.title,
required this.description,
required this.price,
required this.availableQuantity,
this.avgRating = 0,
this.numRatings = 0,
});
/// Unique product id
final String id;
final String imageUrl;
final String title;
final String description;
final double price;
final int availableQuantity;
final double avgRating;
final int numRatings;
}
final kTestProducts = [
const Product(
id: '1',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fbruschetta-plate.jpg?alt=media&token=79a1ee8a-c626-42fb-9c5d-842b1db1ac53',
title: 'Bruschetta plate',
description: 'Lorem ipsum',
price: 15,
availableQuantity: 5,
),
Product(
id: '2',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fmozzarella-plate.jpg?alt=media&token=f3609f0e-a44b-4d2d-99df-9ba08e87f990',
title: 'Mozzarella plate' * 2,
description: 'Lorem ipsum',
price: 13,
availableQuantity: 5,
),
Product(
id: '3',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fpasta-plate.jpg?alt=media&token=0885722c-501b-4e49-a1cc-3fba2c86e9ce',
title: 'Pasta plate' * 3,
description: 'Lorem ipsum',
price: 17,
availableQuantity: 5,
),
const Product(
id: '4',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fpiggy-blue.jpg?alt=media&token=ec9603ed-5db3-48b0-9bfe-42d7b473d809',
title: 'Piggy Bank Blue',
description: 'Lorem ipsum',
price: 12,
availableQuantity: 5,
),
Product(
id: '5',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fpiggy-green.jpg?alt=media&token=9db42cd5-8d0a-4bab-9b67-5ff7244107e3',
title: 'Piggy Bank Green' * 2,
description: 'Lorem ipsum',
price: 12,
availableQuantity: 10,
),
Product(
id: '6',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fpiggy-pink.jpg?alt=media&token=eaddea19-243c-4d45-9075-1b104241f862',
title: 'Piggy Bank Pink' * 3,
description: 'Lorem ipsum',
price: 12,
availableQuantity: 10,
),
const Product(
id: '7',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fpizza-plate.jpg?alt=media&token=0099ff6d-b9e0-4fb7-8d82-118dfdd655a5',
title: 'Pizza plate',
description: 'Lorem ipsum',
price: 18,
availableQuantity: 10,
),
Product(
id: '8',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fplate-and-bowl.jpg?alt=media&token=b371bda7-63a3-4e64-b490-94f55569cc05',
title: 'Plate and Bowl' * 2,
description: 'Lorem ipsum',
price: 21,
availableQuantity: 10,
),
Product(
id: '9',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fsalt-pepper-lemon.jpg?alt=media&token=1806483a-b3f7-40d1-85fa-54b4332510f4',
title: 'Salt and pepper lemon' * 3,
description: 'Lorem ipsum',
price: 11,
availableQuantity: 10,
),
const Product(
id: '10',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fsalt-pepper-olives.jpg?alt=media&token=fd28eba5-ac88-4ca3-bed1-4cca4447a131',
title: 'Salt and pepper olives',
description: 'Lorem ipsum',
price: 11,
availableQuantity: 10,
),
Product(
id: '11',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fsnacks-plate.jpg?alt=media&token=64509406-adc1-45f4-af28-eb01f4cd24b3',
title: 'Snacks plate' * 2,
description: 'Lorem ipsum',
price: 24,
availableQuantity: 10,
),
Product(
id: '12',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fflowers-plate.jpg?alt=media&token=1181a205-9cb9-41e1-a80c-f89886cd5e76',
title: 'Flowers plate' * 3,
description: 'Lorem ipsum',
price: 22,
availableQuantity: 10,
),
const Product(
id: '13',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fjuicer-citrus-fruits.jpg?alt=media&token=00edf667-e957-42b3-9b15-a0e1aacc683d',
title: 'Juicer for citrus fruits',
description: 'Lorem ipsum',
price: 14,
availableQuantity: 10,
),
Product(
id: '14',
imageUrl:
'https://firebasestorage.googleapis.com/v0/b/ecommerce-app-scratch.appspot.com/o/products%2Fhoney-pot.jpg?alt=media&token=0de0f72f-c1e2-4422-a680-5e623dafec01',
title: 'Honey pot' * 2,
description: 'Lorem ipsum',
price: 16,
availableQuantity: 10,
),
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment