Commit 079db95b authored by Adam Barth's avatar Adam Barth Committed by GitHub

Switch DatePicker to SliverGrid (#7890)

After this patch, the old grid code is not used in the framework.
parent 31e2a500
......@@ -6,6 +6,7 @@ import 'dart:async';
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 @@ class _DatePickerHeader extends StatelessWidget {
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 @@ class DayPicker extends StatelessWidget {
@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 @@ class DayPicker extends StatelessWidget {
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 @@ class DayPicker extends StatelessWidget {
onTap: () {
onChanged(dayToBuild);
},
child: dayWidget
child: dayWidget,
);
}
......@@ -284,18 +293,18 @@ class DayPicker extends StatelessWidget {
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 @@ class MonthPicker extends StatefulWidget {
@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 @@ class _MonthPickerState extends State<MonthPicker> {
firstDate: config.firstDate,
lastDate: config.lastDate,
displayedMonth: monthToBuild,
selectableDayPredicate: config.selectableDayPredicate
selectableDayPredicate: config.selectableDayPredicate,
));
}
return result;
......@@ -460,7 +469,7 @@ class _MonthPickerState extends State<MonthPicker> {
itemCount: _monthDelta(config.firstDate, config.lastDate) + 1,
itemBuilder: _buildItems,
duration: _kMonthScrollDuration,
onPageChanged: _handleMonthPageChanged
onPageChanged: _handleMonthPageChanged,
),
new Positioned(
top: 0.0,
......@@ -468,8 +477,8 @@ class _MonthPickerState extends State<MonthPicker> {
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 @@ class _MonthPickerState extends State<MonthPicker> {
child: new IconButton(
icon: new Icon(Icons.chevron_right),
tooltip: 'Next month',
onPressed: _isDisplayingLastMonth ? null : _handleNextMonth
)
)
]
)
onPressed: _isDisplayingLastMonth ? null : _handleNextMonth,
),
),
],
),
);
}
......@@ -516,7 +525,7 @@ class YearPicker extends StatefulWidget {
@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 @@ class _DatePickerDialog extends StatefulWidget {
this.initialDate,
this.firstDate,
this.lastDate,
this.selectableDayPredicate
this.selectableDayPredicate,
}) : super(key: key);
final DateTime initialDate;
......@@ -639,7 +648,7 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
onChanged: _handleDayChanged,
firstDate: config.firstDate,
lastDate: config.lastDate,
selectableDayPredicate: config.selectableDayPredicate
selectableDayPredicate: config.selectableDayPredicate,
);
case _DatePickerMode.year:
return new YearPicker(
......@@ -647,7 +656,7 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
selectedDate: _selectedDate,
onChanged: _handleYearChanged,
firstDate: config.firstDate,
lastDate: config.lastDate
lastDate: config.lastDate,
);
}
return null;
......@@ -659,21 +668,21 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
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 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
selectedDate: _selectedDate,
mode: _mode,
onModeChanged: _handleModeChanged,
orientation: orientation
orientation: orientation,
);
assert(orientation != null);
switch (orientation) {
......@@ -693,8 +702,8 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
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 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[picker, actions]
)
)
)
]
)
children: <Widget>[picker, actions],
),
),
),
],
),
);
}
return null;
......@@ -748,7 +757,7 @@ Future<DateTime> showDatePicker({
@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 @@ Future<DateTime> showDatePicker({
initialDate: initialDate,
firstDate: firstDate,
lastDate: lastDate,
selectableDayPredicate: selectableDayPredicate
selectableDayPredicate: selectableDayPredicate,
)
);
}
......@@ -79,8 +79,20 @@ class SliverChildBuilderDelegate extends SliverChildDelegate {
// /// 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 @@ class SliverChildListDelegate extends SliverChildDelegate {
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
......
......@@ -41,16 +41,16 @@ void main() {
setState(() {
_selectedDate = value;
});
}
)
)
)
},
),
),
),
);
}
)
)
]
)
},
),
),
],
),
);
await tester.tapAt(const Point(50.0, 100.0));
......@@ -79,7 +79,7 @@ void main() {
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 @@ void main() {
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));
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment