Last active
July 18, 2022 19:14
-
-
Save rydmike/e199cb754fc08f4e1500efc96e322eee to your computer and use it in GitHub Desktop.
EXAMPLE: Padding Slivers with SliverPadding and demo of why Padding does not work
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | |
), | |
), | |
) | |
], | |
), | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated to null safe version and to use ScrollConfiguration to avoid double scrollbars on desktop and web.