Skip to content

Instantly share code, notes, and snippets.

@rydmike
Created February 21, 2020 12:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rydmike/5e43bde9df72180982398fd4eef1cd87 to your computer and use it in GitHub Desktop.
Save rydmike/5e43bde9df72180982398fd4eef1cd87 to your computer and use it in GitHub Desktop.
More GridView Tests and Testing const versus static const class members in Flutter const widgets
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
const double kMySize = 20.0;
const Color kMyGreen = Color(0xFF388E3C);
class MyConsts {
// Private constructor so the class cannot be externally instantiated
// This also hides the code completion, but only when the class
// is in another imported file, so it cannot be demoed in DartPad
MyConsts._();
static const double mySize = 20.0;
static const Color myOrange = Color(0xFFFF7043);
}
void main() {
return runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// On a device this [setSystemUIOverlayStyle] call will make your AppBar cool
// on Android. It also helps with the AppBar effect shown just for fun in
// Example 4 by also making the transparent gradient AppBar
// visible on the top system status icons and it also in the other examples
// makes it so that the AppBar and status icons area always uses the
// same color as the one used in Flutter's AppBar
// and not standard Android two toned one, so it looks like an iPhone :)
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
systemNavigationBarColor: Colors.grey[100],
statusBarColor: Colors.transparent,
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 Grid and Other Tests'),
);
}
}
class ExamplesPage extends StatelessWidget {
ExamplesPage({Key key, 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: 20),
child: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(),
),
Container(
width: 350,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text('DEMO - Const versus static const class',
style: TextStyle(fontWeight: FontWeight.bold)),
Text(
'This page shows an example of using const constants versus static '
'const properties'),
RaisedButton(
child: Text('Flutter consts experiment'),
onPressed: () => ConstsDemoPage.show(context,
title: 'Flutter Consts Experiment'),
),
const SizedBox(height: 20),
Text('ISSUE - WEB Shadows',
style: TextStyle(fontWeight: FontWeight.bold)),
Text('This page shows some issues with shadows on WEB, they '
'spread out way too much compared to same shadow on a device.'),
RaisedButton(
child: Text('Flutter Web shadows issue'),
onPressed: () => ShadowsIssuePage.show(context,
title: 'Shadows WEB issue'),
),
const 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.'),
RaisedButton(
child: Text('Padding on Gridview builder'),
onPressed: () => GridViewBuilderPage.show(context,
title: 'Padding a GridView builder'),
),
const SizedBox(height: 20),
Text('EXAMPLE 2 - Padding on SliverGrid',
style: TextStyle(fontWeight: FontWeight.bold)),
Text(
'Padding on SliverGrid is tricker, wrapping entire CustomScrollView '
'with padding FAILS, it will cover shadows!'),
RaisedButton(
child: Text('Padding Slivers and SliverGrid'),
onPressed: () => SliverGridFailPage.show(context,
title: 'Padding a SliverGrid FAIL'),
),
const SizedBox(height: 20),
Text('EXAMPLE 3 - Padding SliverGrid with SliverPadding',
style: TextStyle(fontWeight: FontWeight.bold)),
Text('Padding on SliverGrid is tricker, use SliverPadding!'),
RaisedButton(
child: Text('Padding Slivers and SliverGrid'),
onPressed: () => SliverGridPage.show(context,
title: 'Padding a SliverGrid OK'),
),
const 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'),
RaisedButton(
child: Text('Padding fancy Slivers and SliverGrid'),
onPressed: () => SliverGridExtPage.show(context,
title: 'Padding a SliverGrid OK'),
),
],
),
),
Expanded(
flex: 1,
child: Container(),
),
],
),
),
);
}
}
// *****************************************************************************
class ConstsDemoPage extends StatelessWidget {
const ConstsDemoPage({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) => ConstsDemoPage(title: title)));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
centerTitle: true,
elevation: 0,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(kMySize),
child: Column(
children: <Widget>[
const Text('I am const sized text',
style: TextStyle(fontSize: kMySize)),
const SizedBox(height: MyConsts.mySize),
const Text('I am static const sized text',
style: TextStyle(fontSize: MyConsts.mySize)),
const SizedBox(height: kMySize),
const Text(
'The static const and plain const worked fine with both const Text and SizedBox',
style: TextStyle(fontSize: 16)),
const SizedBox(height: kMySize),
Text('Trying const Cards, with const color',
style: TextStyle(fontSize: 16)),
const Card(
elevation: 3,
margin: EdgeInsets.all(0),
color: kMyGreen,
child: const SizedBox(
height: 100,
width: double.infinity,
),
),
const SizedBox(height: MyConsts.mySize),
Text('Trying const Cards, with static const color',
style: TextStyle(fontSize: 16)),
const Card(
elevation: 3,
margin: EdgeInsets.all(0),
color: MyConsts.myOrange,
child: const SizedBox(
height: 100,
width: double.infinity,
),
),
const SizedBox(height: MyConsts.mySize),
Text('Trying const Cards, with Material color',
style: TextStyle(fontSize: 16)),
const Card(
elevation: 3,
margin: EdgeInsets.all(0),
color: Colors.blueAccent,
child: const SizedBox(
height: 100,
width: double.infinity,
),
),
const SizedBox(height: 20),
const SelectableText(
'All these examples worked fine. By the way, this text is selectable text. '
'The other texts above are not selectable. '
'You can almost also select this text on web, but still cannot copy '
'it on WEB, bummer.'),
],
),
),
),
);
}
}
// *****************************************************************************
class GridItem extends StatelessWidget {
const GridItem({Key key, this.title, this.color, this.height, 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(10),
child: Column(
children: <Widget>[
Text(
title,
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
if (height != null && height > 0) SizedBox(height: height),
if (height != null && height > 0)
Text(bodyText,
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold)),
],
),
);
}
}
// *****************************************************************************
class ShadowsIssuePage extends StatelessWidget {
const ShadowsIssuePage({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) => ShadowsIssuePage(title: title)));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 30, 20, 50),
child: Column(
children: <Widget>[
Text('Shadows on Web look incorrect',
style: TextStyle(fontSize: 25)),
SizedBox(height: 10),
Text('Shadows bleed too much compared to device rendering',
style: TextStyle(fontSize: 16)),
const SizedBox(height: 20),
Card(
elevation: 0,
margin: EdgeInsets.all(0),
color: Colors.indigo[100],
child: Container(
child: Center(child: Text('Material Card with elevation 0')),
height: 100,
),
),
const SizedBox(height: 20),
Card(
elevation: 5,
margin: EdgeInsets.all(0),
color: Colors.indigo[100],
child: Container(
child: Center(child: Text('Material Card with elevation 5')),
height: 100,
),
),
const SizedBox(height: 20),
Card(
elevation: 10,
margin: EdgeInsets.all(0),
color: Colors.indigo[100],
child: Container(
child: Center(child: Text('Material Card with elevation 10')),
height: 100,
),
),
const SizedBox(height: 20),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.indigo.withOpacity(0.7),
offset: Offset(3, 4),
blurRadius: 6,
spreadRadius: 3,
),
],
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Colors.indigo[100],
),
child: Center(child: Text('Container with custom BoxShadow')),
height: 100,
),
),
const SizedBox(height: 20),
SelectableText(
'The fonts on WEB are also fuzzier, like too much antialias'),
SelectableText(
'The shadow issue is reported here: https://github.com/flutter/flutter/issues/32215 '),
],
),
),
),
);
}
}
// *****************************************************************************
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(10),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 2,
),
itemCount: _gridItems.length,
itemBuilder: (context, index) => Card(
elevation: 6,
child: _gridItems[index],
),
),
),
);
}
}
// *****************************************************************************
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: Padding(
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
child: CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate([
SizedBox(height: 20),
Text(
'SliverGrid Padding FAIL',
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 uggly = 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,
),
),
],
),
),
),
);
}
}
// *****************************************************************************
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: CustomScrollView(
slivers: <Widget>[
SliverPadding(
padding: const 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: const 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,
),
),
)
],
),
),
);
}
}
// *****************************************************************************
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,
// Fancy gradient partially transparent AppBar
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: CustomScrollView(
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
sliver: SliverList(
delegate: SliverChildListDelegate([
// We need to add back the padding we removed by allowing scrolling under the toolbar
SizedBox(
height: 10 +
MediaQuery.of(context).padding.top +
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!'),
SizedBox(height: 10),
Text('SliverPadding also works with package '
'StaggaredGrid and its SliverStaggaredGrid but that cannot be '
'shown in DartPad, but here is an another example showing it: '),
SizedBox(height: 5),
SelectableText(
'https://gist.github.com/rydmike/5997737351268ad08e35e9f406e73f39'),
SizedBox(height: 20),
]),
),
),
SliverPadding(
padding: const 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,
),
),
)
],
),
),
);
}
}
@rydmike
Copy link
Author

rydmike commented Feb 21, 2020

As a result of the discussions on this thread I added to my SliverGrid experiments a test to see how const versus static const in classes behave when used for const Widgets. It is the first button in this updated experiment/test. You can run it in DartPad here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment