-
-
Save rydmike/e199cb754fc08f4e1500efc96e322eee to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart'; | |
import 'package:flutter/services.dart'; | |
void main() { | |
return runApp(MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
SystemChrome.setSystemUIOverlayStyle( | |
SystemUiOverlayStyle( | |
systemNavigationBarColor: Colors.grey[100], | |
statusBarColor: Colors.indigo, | |
statusBarIconBrightness: Brightness.light, | |
systemNavigationBarIconBrightness: Brightness.dark, | |
), | |
); | |
return MaterialApp( | |
title: 'Flutter Grids', | |
debugShowCheckedModeBanner: false, | |
theme: ThemeData( | |
primarySwatch: Colors.indigo, | |
scaffoldBackgroundColor: Colors.grey[100], | |
buttonTheme: ButtonThemeData( | |
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.indigo), | |
textTheme: ButtonTextTheme.primary, | |
), | |
), | |
home: ExamplesPage(title: 'Flutter GridView Padding Examples'), | |
); | |
} | |
} | |
class ExamplesPage extends StatelessWidget { | |
ExamplesPage({Key? key, required this.title}) : super(key: key); | |
final String title; | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(title), | |
centerTitle: true, | |
elevation: 0, | |
), | |
body: SingleChildScrollView( | |
padding: EdgeInsets.only(top: 40), | |
child: Row( | |
children: <Widget>[ | |
Expanded( | |
flex: 1, | |
child: Container(), | |
), | |
Container( | |
width: 410, | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
crossAxisAlignment: CrossAxisAlignment.stretch, | |
children: <Widget>[ | |
SizedBox(height: 20), | |
Text('EXAMPLE 1 - Simple grid padding case', | |
style: TextStyle(fontWeight: FontWeight.bold)), | |
Text( | |
'Padding on GridView builder is simple, it has a standard ' | |
'padding property, just use it.'), | |
ElevatedButton( | |
child: Text('Padding on Gridview builder'), | |
onPressed: () => GridViewBuilderPage.show(context, | |
title: 'Padding a GridView builder'), | |
), | |
SizedBox(height: 20), | |
Text('EXAMPLE 2 - Padding on SliverGrid', | |
style: TextStyle(fontWeight: FontWeight.bold)), | |
Text( | |
'Padding on SliverGrid is trickier, wrapping entire CustomScrollView ' | |
'with padding FAILS, it will cover the shadows!'), | |
ElevatedButton( | |
child: Text('Padding Slivers and SliverGrid'), | |
onPressed: () => SliverGridFailPage.show(context, | |
title: 'Padding a CustomScrollView and SliverGrid'), | |
), | |
SizedBox(height: 20), | |
Text('EXAMPLE 3 - Padding SliverGrid with SliverPadding', | |
style: TextStyle(fontWeight: FontWeight.bold)), | |
Text('Padding on SliverGrid is trickier, use SliverPadding!'), | |
ElevatedButton( | |
child: Text('Padding Slivers and SliverGrid'), | |
onPressed: () => SliverGridPage.show(context, | |
title: 'Padding a CustomScrollView and SliverGrid'), | |
), | |
SizedBox(height: 20), | |
Text('EXAMPLE 4 - SliverGrid fancy pants', | |
style: TextStyle(fontWeight: FontWeight.bold)), | |
Text('Padding a SliverGrid works on extend behind ' | |
'AppBar and fancy transparent gradient AppBar too'), | |
ElevatedButton( | |
child: Text('Padding fancy Slivers and SliverGrid'), | |
onPressed: () => SliverGridExtPage.show(context, | |
title: 'Padding a CustomScrollView and SliverGrid'), | |
), | |
], | |
), | |
), | |
Expanded( | |
flex: 1, | |
child: Container(), | |
), | |
], | |
), | |
), | |
); | |
} | |
} | |
// ***************************************************************************** | |
class GridItem extends StatelessWidget { | |
const GridItem( | |
{Key? key, | |
required this.title, | |
required this.color, | |
this.height = 0, | |
this.bodyText = ''}) | |
: super(key: key); | |
final String title; | |
final Color color; | |
final double height; | |
final String bodyText; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: color, | |
padding: const EdgeInsets.all(20), | |
child: Column( | |
children: <Widget>[ | |
Text( | |
title, | |
style: TextStyle( | |
color: Colors.white, | |
fontSize: 20, | |
), | |
), | |
if (height > 0) SizedBox(height: height), | |
if (height > 0 && bodyText != '') | |
Text(bodyText, | |
style: TextStyle( | |
color: Colors.white, fontWeight: FontWeight.bold)), | |
], | |
), | |
); | |
} | |
} | |
// ***************************************************************************** | |
// Example 1 | |
class GridViewBuilderPage extends StatelessWidget { | |
const GridViewBuilderPage({Key? key, this.title = ''}) : super(key: key); | |
final String title; | |
static Future<void> show(BuildContext context, {String title = ''}) async { | |
await Navigator.of(context).push(MaterialPageRoute( | |
builder: (context) => GridViewBuilderPage(title: title))); | |
} | |
@override | |
Widget build(BuildContext context) { | |
var _gridItems = List<GridItem>.generate(400, (index) { | |
return GridItem( | |
title: 'Tile nr ${index + 1}', | |
color: Colors.primaries[index % Colors.primaries.length][800]!); | |
}); | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(title), | |
centerTitle: true, | |
elevation: 0, | |
), | |
body: Scrollbar( | |
child: GridView.builder( | |
padding: EdgeInsets.all(15), | |
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( | |
crossAxisCount: 3, | |
mainAxisSpacing: 15, | |
crossAxisSpacing: 15, | |
childAspectRatio: 2, | |
), | |
itemCount: _gridItems.length, | |
itemBuilder: (context, index) => Card( | |
elevation: 12, | |
child: _gridItems[index], | |
), | |
), | |
), | |
); | |
} | |
} | |
// ***************************************************************************** | |
// Example 2 | |
class SliverGridFailPage extends StatelessWidget { | |
const SliverGridFailPage({Key? key, this.title = ''}) : super(key: key); | |
final String title; | |
static Future<void> show(BuildContext context, {String title = ''}) async { | |
await Navigator.of(context).push(MaterialPageRoute( | |
builder: (context) => SliverGridFailPage(title: title))); | |
} | |
@override | |
Widget build(BuildContext context) { | |
var _gridItems = List<GridItem>.generate(400, (index) { | |
return GridItem( | |
title: 'Tile nr ${index + 1}', | |
color: Colors.primaries[index % Colors.primaries.length][800]!); | |
}); | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(title), | |
centerTitle: true, | |
elevation: 0, | |
), | |
body: Scrollbar( | |
child: ScrollConfiguration( | |
behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), | |
child: Padding( | |
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0), | |
child: CustomScrollView( | |
slivers: <Widget>[ | |
SliverList( | |
delegate: SliverChildListDelegate([ | |
SizedBox(height: 20), | |
Text( | |
'SliverGrid FAILED Padding', | |
style: Theme.of(context).textTheme.headline4, | |
), | |
Text('Texts and header in own SliverList so that we can ' | |
'scroll them with the scrolling grid. If we WRAP the ' | |
'CustomScrollView in a Padding, the result is ugly = FAIL! ' | |
'The ELEVATION shadows will be covered by the padding!'), | |
SizedBox(height: 20), | |
]), | |
), | |
SliverGrid( | |
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( | |
crossAxisCount: 3, | |
mainAxisSpacing: 15, | |
crossAxisSpacing: 15, | |
childAspectRatio: 2, | |
), | |
delegate: SliverChildBuilderDelegate( | |
(ctx, index) { | |
return Card( | |
elevation: 6, | |
child: _gridItems[index], | |
); | |
}, | |
childCount: _gridItems.length, | |
), | |
), | |
], | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
// ***************************************************************************** | |
// Example 3 | |
class SliverGridPage extends StatelessWidget { | |
const SliverGridPage({Key? key, this.title = ''}) : super(key: key); | |
final String title; | |
static Future<void> show(BuildContext context, {String title = ''}) async { | |
await Navigator.of(context).push( | |
MaterialPageRoute(builder: (context) => SliverGridPage(title: title))); | |
} | |
@override | |
Widget build(BuildContext context) { | |
var _gridItems = List<GridItem>.generate(400, (index) { | |
return GridItem( | |
title: 'Tile nr ${index + 1}', | |
color: Colors.primaries[index % Colors.primaries.length][800]!); | |
}); | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(title), | |
centerTitle: true, | |
elevation: 0, | |
), | |
body: Scrollbar( | |
child: ScrollConfiguration( | |
behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), | |
child: CustomScrollView( | |
slivers: <Widget>[ | |
SliverPadding( | |
padding: EdgeInsets.fromLTRB(15, 0, 15, 0), | |
sliver: SliverList( | |
delegate: SliverChildListDelegate([ | |
SizedBox(height: 20), | |
Text( | |
'SliverGrid OK Padding', | |
style: Theme.of(context).textTheme.headline4, | |
), | |
Text('Texts and header in own SliverList so that we can ' | |
'scroll them with the scrolling grid. To get the ' | |
'Padding effect, we must wrap each Sliver in a ' | |
'SliverPadding!'), | |
SizedBox(height: 20), | |
]), | |
), | |
), | |
SliverPadding( | |
padding: EdgeInsets.fromLTRB(15, 0, 15, 0), | |
sliver: SliverGrid( | |
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( | |
crossAxisCount: 3, | |
mainAxisSpacing: 15, | |
crossAxisSpacing: 15, | |
childAspectRatio: 2, | |
), | |
delegate: SliverChildBuilderDelegate( | |
(ctx, index) { | |
return Card( | |
elevation: 6, | |
child: _gridItems[index], | |
); | |
}, | |
childCount: _gridItems.length, | |
), | |
), | |
) | |
], | |
), | |
), | |
), | |
); | |
} | |
} | |
// ***************************************************************************** | |
// Example 4 | |
class SliverGridExtPage extends StatelessWidget { | |
const SliverGridExtPage({Key? key, this.title = ''}) : super(key: key); | |
final String title; | |
static Future<void> show(BuildContext context, {String title = ''}) async { | |
await Navigator.of(context).push(MaterialPageRoute( | |
builder: (context) => SliverGridExtPage(title: title))); | |
} | |
@override | |
Widget build(BuildContext context) { | |
var _gridItems = List<GridItem>.generate(400, (index) { | |
return GridItem( | |
title: 'Tile nr ${index + 1}', | |
color: Colors.primaries[index % Colors.primaries.length][800]!); | |
}); | |
return Scaffold( | |
extendBodyBehindAppBar: true, | |
extendBody: true, | |
appBar: AppBar( | |
title: Text(title), | |
centerTitle: true, | |
elevation: 0, | |
backgroundColor: Colors.transparent, | |
flexibleSpace: Container( | |
decoration: BoxDecoration( | |
gradient: LinearGradient( | |
begin: Alignment.topLeft, | |
end: Alignment.topRight, | |
colors: [ | |
Colors.indigo, | |
Colors.indigo.withOpacity(0.6), | |
], | |
), | |
), | |
child: null, | |
), | |
), | |
body: Scrollbar( | |
child: ScrollConfiguration( | |
behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), | |
child: CustomScrollView( | |
slivers: <Widget>[ | |
SliverPadding( | |
padding: EdgeInsets.fromLTRB(15, 0, 15, 0), | |
sliver: SliverList( | |
delegate: SliverChildListDelegate([ | |
SizedBox(height: 20 + kToolbarHeight), | |
Text( | |
'SliverGrid OK Padding', | |
style: Theme.of(context).textTheme.headline4, | |
), | |
Text('Texts and header in own SliverList so that we can ' | |
'scroll them with the scrolling grid. Here with scroll ' | |
'behind a fancy gradient transparent AppBar!'), | |
Text('SliverPadding also works with package ' | |
'StaggeredGrid and its SliverStaggeredGrid but that cannot be ' | |
'shown in DartPad, but here is an another example using it: '), | |
SelectableText( | |
'https://gist.github.com/rydmike/5997737351268ad08e35e9f406e73f39'), | |
SizedBox(height: 20), | |
]), | |
), | |
), | |
SliverPadding( | |
padding: EdgeInsets.fromLTRB(15, 0, 15, 0), | |
sliver: SliverGrid( | |
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( | |
crossAxisCount: 3, | |
mainAxisSpacing: 15, | |
crossAxisSpacing: 15, | |
childAspectRatio: 2, | |
), | |
delegate: SliverChildBuilderDelegate( | |
(ctx, index) { | |
return Card( | |
elevation: 6, | |
child: _gridItems[index], | |
); | |
}, | |
childCount: _gridItems.length, | |
), | |
), | |
) | |
], | |
), | |
), | |
), | |
); | |
} | |
} |
Thx and lol, because how on earth did you even find this old thing! 😃
Although this one contains some nice pointers, I should perhaps add it somewhere on my GitHub Pages site https://rydmike.com/gridview to make this and few other ones like it easier find...
19.12.2020 Updated: Removed the web shadows issues, since it is no longer an issue, at least not to the extent it was when I wrote this demo. It was thus a bit confusing to have in here. Also increased the elevation of the demo card to show the difference better now that the elevation is not as exaggerated as it was before we need to use a bit more elevation to show the difference.
Right, the web shadows were a big issue. Thank you for helping improve the web fidelity with your demos and issues. Creating reproducible samples takes quite a bit of time!
Updated to null safe version and to use ScrollConfiguration to avoid double scrollbars on desktop and web.
Nice, I'm seeing you everywhere now 👍