Switch DatePicker to SliverGrid (#7890)

After this patch, the old grid code is not used in the framework.
diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart
index 84aa8f1..5232fab 100644
--- a/packages/flutter/lib/src/material/date_picker.dart
+++ b/packages/flutter/lib/src/material/date_picker.dart
@@ -6,6 +6,7 @@
 import 'dart:math' as math;
 
 import 'package:flutter/foundation.dart';
+import 'package:flutter/rendering.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
 import 'package:intl/date_symbols.dart';
@@ -122,32 +123,40 @@
         children: <Widget>[
           new GestureDetector(
             onTap: () => _handleChangeMode(_DatePickerMode.year),
-            child: new Text(new DateFormat('yyyy').format(selectedDate), style: yearStyle)
+            child: new Text(new DateFormat('yyyy').format(selectedDate), style: yearStyle),
           ),
           new GestureDetector(
             onTap: () => _handleChangeMode(_DatePickerMode.day),
-            child: new Text(new DateFormat('E, MMM\u00a0d').format(selectedDate), style: dayStyle)
+            child: new Text(new DateFormat('E, MMM\u00a0d').format(selectedDate), style: dayStyle),
           ),
-        ]
-      )
+        ],
+      ),
     );
   }
 }
 
-class _DayPickerGridDelegate extends GridDelegateWithInOrderChildPlacement {
+class _DayPickerGridDelegate extends SliverGridDelegate {
+  const _DayPickerGridDelegate();
+
   @override
-  GridSpecification getGridSpecification(BoxConstraints constraints, int childCount) {
+  SliverGridLayout getLayout(SliverConstraints constraints) {
     final int columnCount = DateTime.DAYS_PER_WEEK;
-    return new GridSpecification.fromRegularTiles(
-      tileWidth: constraints.maxWidth / columnCount,
-      tileHeight: math.min(_kDayPickerRowHeight, constraints.maxHeight / (_kMaxDayPickerRowCount + 1)),
-      columnCount: columnCount,
-      rowCount: (childCount / columnCount).ceil()
+    final double tileWidth = constraints.crossAxisExtent / columnCount;
+    final double tileHeight = math.min(_kDayPickerRowHeight, constraints.viewportMainAxisExtent / (_kMaxDayPickerRowCount + 1));
+    return new SliverGridRegularTileLayout(
+      crossAxisCount: columnCount,
+      mainAxisStride: tileHeight,
+      crossAxisStride: tileWidth,
+      childMainAxisExtent: tileHeight,
+      childCrossAxisExtent: tileWidth,
     );
   }
+
+  @override
+  bool shouldRelayout(_DayPickerGridDelegate oldDelegate) => false;
 }
 
-final _DayPickerGridDelegate _kDayPickerGridDelegate = new _DayPickerGridDelegate();
+const _DayPickerGridDelegate _kDayPickerGridDelegate = const _DayPickerGridDelegate();
 
 /// Displays the days of a given month and allows choosing a day.
 ///
@@ -173,7 +182,7 @@
     @required this.firstDate,
     @required this.lastDate,
     @required this.displayedMonth,
-    this.selectableDayPredicate
+    this.selectableDayPredicate,
   }) : super(key: key) {
     assert(selectedDate != null);
     assert(currentDate != null);
@@ -258,8 +267,8 @@
         Widget dayWidget = new Container(
           decoration: decoration,
           child: new Center(
-            child: new Text(day.toString(), style: itemStyle)
-          )
+            child: new Text(day.toString(), style: itemStyle),
+          ),
         );
 
         if (!disabled) {
@@ -268,7 +277,7 @@
             onTap: () {
               onChanged(dayToBuild);
             },
-            child: dayWidget
+            child: dayWidget,
           );
         }
 
@@ -284,18 +293,18 @@
             height: _kDayPickerRowHeight,
             child: new Center(
               child: new Text(new DateFormat('yMMMM').format(displayedMonth),
-                style: themeData.textTheme.subhead
-              )
-            )
+                style: themeData.textTheme.subhead,
+              ),
+            ),
           ),
           new Flexible(
-            child: new CustomGrid(
-              delegate: _kDayPickerGridDelegate,
-              children: labels
-            )
-          )
-        ]
-      )
+            child: new GridView.custom(
+              gridDelegate: _kDayPickerGridDelegate,
+              childrenDelegate: new SliverChildListDelegate(labels, addRepaintBoundaries: false),
+            ),
+          ),
+        ],
+      ),
     );
   }
 }
@@ -322,7 +331,7 @@
     @required this.onChanged,
     @required this.firstDate,
     @required this.lastDate,
-    this.selectableDayPredicate
+    this.selectableDayPredicate,
   }) : super(key: key) {
     assert(selectedDate != null);
     assert(onChanged != null);
@@ -410,7 +419,7 @@
         firstDate: config.firstDate,
         lastDate: config.lastDate,
         displayedMonth: monthToBuild,
-        selectableDayPredicate: config.selectableDayPredicate
+        selectableDayPredicate: config.selectableDayPredicate,
       ));
     }
     return result;
@@ -460,7 +469,7 @@
             itemCount: _monthDelta(config.firstDate, config.lastDate) + 1,
             itemBuilder: _buildItems,
             duration: _kMonthScrollDuration,
-            onPageChanged: _handleMonthPageChanged
+            onPageChanged: _handleMonthPageChanged,
           ),
           new Positioned(
             top: 0.0,
@@ -468,8 +477,8 @@
             child: new IconButton(
               icon: new Icon(Icons.chevron_left),
               tooltip: 'Previous month',
-              onPressed: _isDisplayingFirstMonth ? null : _handlePreviousMonth
-            )
+              onPressed: _isDisplayingFirstMonth ? null : _handlePreviousMonth,
+            ),
           ),
           new Positioned(
             top: 0.0,
@@ -477,11 +486,11 @@
             child: new IconButton(
               icon: new Icon(Icons.chevron_right),
               tooltip: 'Next month',
-              onPressed: _isDisplayingLastMonth ? null : _handleNextMonth
-            )
-          )
-        ]
-      )
+              onPressed: _isDisplayingLastMonth ? null : _handleNextMonth,
+            ),
+          ),
+        ],
+      ),
     );
   }
 
@@ -516,7 +525,7 @@
     @required this.selectedDate,
     @required this.onChanged,
     @required this.firstDate,
-    @required this.lastDate
+    @required this.lastDate,
   }) : super(key: key) {
     assert(selectedDate != null);
     assert(onChanged != null);
@@ -576,7 +585,7 @@
     this.initialDate,
     this.firstDate,
     this.lastDate,
-    this.selectableDayPredicate
+    this.selectableDayPredicate,
   }) : super(key: key);
 
   final DateTime initialDate;
@@ -639,7 +648,7 @@
           onChanged: _handleDayChanged,
           firstDate: config.firstDate,
           lastDate: config.lastDate,
-          selectableDayPredicate: config.selectableDayPredicate
+          selectableDayPredicate: config.selectableDayPredicate,
         );
       case _DatePickerMode.year:
         return new YearPicker(
@@ -647,7 +656,7 @@
           selectedDate: _selectedDate,
           onChanged: _handleYearChanged,
           firstDate: config.firstDate,
-          lastDate: config.lastDate
+          lastDate: config.lastDate,
         );
     }
     return null;
@@ -659,21 +668,21 @@
       child: new SizedBox(
         height: _kMaxDayPickerHeight,
         child: _buildPicker(),
-      )
+      ),
     );
     Widget actions = new ButtonTheme.bar(
       child: new ButtonBar(
         children: <Widget>[
           new FlatButton(
             child: new Text('CANCEL'),
-            onPressed: _handleCancel
+            onPressed: _handleCancel,
           ),
           new FlatButton(
             child: new Text('OK'),
-            onPressed: _handleOk
+            onPressed: _handleOk,
           ),
-        ]
-      )
+        ],
+      ),
     );
 
     return new Dialog(
@@ -683,7 +692,7 @@
             selectedDate: _selectedDate,
             mode: _mode,
             onModeChanged: _handleModeChanged,
-            orientation: orientation
+            orientation: orientation,
           );
           assert(orientation != null);
           switch (orientation) {
@@ -693,8 +702,8 @@
                 child: new Column(
                   mainAxisSize: MainAxisSize.min,
                   crossAxisAlignment: CrossAxisAlignment.stretch,
-                  children: <Widget>[header, picker, actions]
-                )
+                  children: <Widget>[header, picker, actions],
+                ),
               );
             case Orientation.landscape:
               return new SizedBox(
@@ -710,12 +719,12 @@
                         child: new Column(
                           mainAxisSize: MainAxisSize.min,
                           crossAxisAlignment: CrossAxisAlignment.stretch,
-                          children: <Widget>[picker, actions]
-                        )
-                      )
-                    )
-                  ]
-                )
+                          children: <Widget>[picker, actions],
+                        ),
+                      ),
+                    ),
+                  ],
+                ),
               );
           }
           return null;
@@ -748,7 +757,7 @@
   @required DateTime initialDate,
   @required DateTime firstDate,
   @required DateTime lastDate,
-  SelectableDayPredicate selectableDayPredicate
+  SelectableDayPredicate selectableDayPredicate,
 }) async {
   assert(!initialDate.isBefore(firstDate), 'initialDate must be on or after firstDate');
   assert(!initialDate.isAfter(lastDate), 'initialDate must be on or before lastDate');
@@ -763,7 +772,7 @@
       initialDate: initialDate,
       firstDate: firstDate,
       lastDate: lastDate,
-      selectableDayPredicate: selectableDayPredicate
+      selectableDayPredicate: selectableDayPredicate,
     )
   );
 }
diff --git a/packages/flutter/lib/src/widgets/sliver.dart b/packages/flutter/lib/src/widgets/sliver.dart
index ea75e10..20d43f7 100644
--- a/packages/flutter/lib/src/widgets/sliver.dart
+++ b/packages/flutter/lib/src/widgets/sliver.dart
@@ -79,8 +79,20 @@
 // /// demand). For example, the body of a dialog box might fit both of these
 // /// conditions.
 class SliverChildListDelegate extends SliverChildDelegate {
-  const SliverChildListDelegate(this.children);
+  const SliverChildListDelegate(this.children, { this.addRepaintBoundaries: true });
 
+  /// Whether to wrap each child in a [RepaintBoundary].
+  ///
+  /// Typically, children in a scrolling container are wrapped in repaint
+  /// boundaries so that they do not need to be repainted as the list scrolls.
+  /// If the children are easy to repaint (e.g., solid color blocks or a short
+  /// snippet of text), it might be more efficient to not add a repaint boundary
+  /// and simply repaint the children during scrolling.
+  ///
+  /// Defaults to true.
+  final bool addRepaintBoundaries;
+
+  /// The widgets to display.
   final List<Widget> children;
 
   @override
@@ -90,7 +102,7 @@
       return null;
     final Widget child = children[index];
     assert(child != null);
-    return new RepaintBoundary.wrap(child, index);
+    return addRepaintBoundaries ? new RepaintBoundary.wrap(child, index) : child;
   }
 
   @override
diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart
index 133c06c..6ff5069 100644
--- a/packages/flutter/test/material/date_picker_test.dart
+++ b/packages/flutter/test/material/date_picker_test.dart
@@ -41,16 +41,16 @@
                           setState(() {
                             _selectedDate = value;
                           });
-                        }
-                      )
-                    )
-                  )
+                        },
+                      ),
+                    ),
+                  ),
                 );
-              }
-            )
-          )
-        ]
-      )
+              },
+            ),
+          ),
+        ],
+      ),
     );
 
     await tester.tapAt(const Point(50.0, 100.0));
@@ -79,7 +79,7 @@
     expect(_selectedDate, equals(new DateTime(2016, DateTime.SEPTEMBER, 25)));
     await tester.pump(const Duration(seconds: 2));
 
-    await tester.scroll(find.byKey(_datePickerKey), const Offset(300.0, 10.0));
+    await tester.scroll(find.byKey(_datePickerKey), const Offset(300.0, 0.0));
     await tester.pump();
     await tester.pump(const Duration(seconds: 2));
     expect(_selectedDate, equals(new DateTime(2016, DateTime.SEPTEMBER, 25)));
@@ -105,17 +105,17 @@
                           firstDate: new DateTime(0),
                           lastDate: new DateTime(9999),
                           onChanged: (DateTime value) { },
-                          selectedDate: new DateTime(2000, DateTime.JANUARY, 1)
-                        )
-                      )
-                    )
-                  )
+                          selectedDate: new DateTime(2000, DateTime.JANUARY, 1),
+                        ),
+                      ),
+                    ),
+                  ),
                 );
-              }
-            )
-          )
-        ]
-      )
+              },
+            ),
+          ),
+        ],
+      ),
     );
     await tester.pump(const Duration(seconds: 5));
   });