Unverified Commit d10e46ea authored by Matt Sullivan's avatar Matt Sullivan Committed by GitHub

Chevrons in month picker are semi-transparent when the month is scrolled (#19363)

* Chevrons in month picker are semi-transparent when the month is scrolled

* Added type missing annotation
parent 6a8f9041
......@@ -524,7 +524,7 @@ class MonthPicker extends StatefulWidget {
_MonthPickerState createState() => new _MonthPickerState();
}
class _MonthPickerState extends State<MonthPicker> {
class _MonthPickerState extends State<MonthPicker> with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
......@@ -533,6 +533,17 @@ class _MonthPickerState extends State<MonthPicker> {
_dayPickerController = new PageController(initialPage: monthPage);
_handleMonthPageChanged(monthPage);
_updateCurrentDate();
// Setup the fade animation for chevrons
_chevronOpacityController = new AnimationController(
duration: const Duration(milliseconds: 500), vsync: this
);
_chevronOpacityAnimation = new Tween<double>(begin: 1.0, end: 0.5).animate(
new CurvedAnimation(
parent: _chevronOpacityController,
curve: Curves.easeInOut,
)
);
}
@override
......@@ -559,6 +570,8 @@ class _MonthPickerState extends State<MonthPicker> {
DateTime _currentDisplayedMonthDate;
Timer _timer;
PageController _dayPickerController;
AnimationController _chevronOpacityController;
Animation<double> _chevronOpacityAnimation;
void _updateCurrentDate() {
_todayDate = new DateTime.now();
......@@ -642,13 +655,25 @@ class _MonthPickerState extends State<MonthPicker> {
children: <Widget>[
new Semantics(
sortKey: _MonthPickerSortKey.calendar,
child: new PageView.builder(
key: new ValueKey<DateTime>(widget.selectedDate),
controller: _dayPickerController,
scrollDirection: Axis.horizontal,
itemCount: _monthDelta(widget.firstDate, widget.lastDate) + 1,
itemBuilder: _buildItems,
onPageChanged: _handleMonthPageChanged,
child: new NotificationListener<ScrollStartNotification>(
onNotification: (_) {
_chevronOpacityController.forward();
return false;
},
child: new NotificationListener<ScrollEndNotification>(
onNotification: (_) {
_chevronOpacityController.reverse();
return false;
},
child: new PageView.builder(
key: new ValueKey<DateTime>(widget.selectedDate),
controller: _dayPickerController,
scrollDirection: Axis.horizontal,
itemCount: _monthDelta(widget.firstDate, widget.lastDate) + 1,
itemBuilder: _buildItems,
onPageChanged: _handleMonthPageChanged,
),
),
),
),
new PositionedDirectional(
......@@ -656,10 +681,13 @@ class _MonthPickerState extends State<MonthPicker> {
start: 8.0,
child: new Semantics(
sortKey: _MonthPickerSortKey.previousMonth,
child: new IconButton(
icon: const Icon(Icons.chevron_left),
tooltip: _isDisplayingFirstMonth ? null : '${localizations.previousMonthTooltip} ${localizations.formatMonthYear(_previousMonthDate)}',
onPressed: _isDisplayingFirstMonth ? null : _handlePreviousMonth,
child: new FadeTransition(
opacity: _chevronOpacityAnimation,
child: new IconButton(
icon: const Icon(Icons.chevron_left),
tooltip: _isDisplayingFirstMonth ? null : '${localizations.previousMonthTooltip} ${localizations.formatMonthYear(_previousMonthDate)}',
onPressed: _isDisplayingFirstMonth ? null : _handlePreviousMonth,
),
),
),
),
......@@ -668,10 +696,13 @@ class _MonthPickerState extends State<MonthPicker> {
end: 8.0,
child: new Semantics(
sortKey: _MonthPickerSortKey.nextMonth,
child: new IconButton(
icon: const Icon(Icons.chevron_right),
tooltip: _isDisplayingLastMonth ? null : '${localizations.nextMonthTooltip} ${localizations.formatMonthYear(_nextMonthDate)}',
onPressed: _isDisplayingLastMonth ? null : _handleNextMonth,
child: new FadeTransition(
opacity: _chevronOpacityAnimation,
child: new IconButton(
icon: const Icon(Icons.chevron_right),
tooltip: _isDisplayingLastMonth ? null : '${localizations.nextMonthTooltip} ${localizations.formatMonthYear(_nextMonthDate)}',
onPressed: _isDisplayingLastMonth ? null : _handleNextMonth,
),
),
),
),
......
......@@ -622,4 +622,65 @@ void _tests() {
semantics.dispose();
});
testWidgets('chervons animate when scrolling month picker', (WidgetTester tester) async {
final Key _datePickerKey = new UniqueKey();
DateTime _selectedDate = new DateTime(2016, DateTime.july, 26);
await tester.pumpWidget(
new MaterialApp(
home: new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Container(
width: 400.0,
child: new SingleChildScrollView(
child: new Material(
child: new MonthPicker(
firstDate: new DateTime(0),
lastDate: new DateTime(9999),
key: _datePickerKey,
selectedDate: _selectedDate,
onChanged: (DateTime value) {
setState(() {
_selectedDate = value;
});
},
),
),
),
);
},
),
)
);
final Finder chevronFinder = find.byType(IconButton);
final List<RenderAnimatedOpacity> chevronRenderers = chevronFinder.evaluate().map(
(Element element) => element.ancestorRenderObjectOfType(
const TypeMatcher<RenderAnimatedOpacity>())).cast<RenderAnimatedOpacity>().toList();
// Initial chevron animation state should be dismissed
// An AlwaysStoppedAnimation is also found and is ignored
for(RenderAnimatedOpacity renderer in chevronRenderers) {
expect(renderer.opacity.value, equals(1.0));
expect(renderer.opacity.status, equals(AnimationStatus.dismissed));
}
// Drag and hold the picker to test for the opacity change
final TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0));
await gesture.moveBy(const Offset(50.0, 100.0));
await tester.pumpAndSettle();
for(RenderAnimatedOpacity renderer in chevronRenderers) {
expect(renderer.opacity.value, equals(0.5));
expect(renderer.opacity.status, equals(AnimationStatus.completed));
}
// Release the drag and test for the opacity to return to original value
await gesture.up();
await tester.pumpAndSettle();
for(RenderAnimatedOpacity renderer in chevronRenderers) {
expect(renderer.opacity.value, equals(1.0));
expect(renderer.opacity.status, equals(AnimationStatus.dismissed));
}
});
}
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