mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fix date picker flickering (#167976)
## Description This PR fixes a `DatePicker` flickering issue observed on some devices with a small display. ### Before When the date picker input dialog is shown the virtual keyboard opens and reduces the available height. The current logic reacts by removing the picker `TextField`. Because there is no more `TextField` the virtual keyboard is hidden and the available height increases, at that moment the `TextField` is shown again. Due to autofocus the virtual keyboard opens which leads to the removal of the `TextField` and so on. https://github.com/user-attachments/assets/deb70f2e-1c8b-47a9-9db6-47bc521e4eb7 ### After When there is not enough vertical space for the input date picker dialog, the header is hidden instead of hiding the `TextField`. https://github.com/user-attachments/assets/14051ee9-3b9a-4467-a4a0-4ee91b4979ea ## Related Issue [Fixes DatePickerDialog text input causes keyboard to open and close on a 480p Android emulator](https://github.com/flutter/flutter/issues/140311). ## Tests Adds 2 tests.
This commit is contained in:
parent
04616f8dde
commit
a46bf190ef
@ -777,13 +777,21 @@ class _DatePickerDialogState extends State<DatePickerDialog> with RestorationMix
|
||||
|
||||
switch (orientation) {
|
||||
case Orientation.portrait:
|
||||
final bool isInputMode =
|
||||
_entryMode.value == DatePickerEntryMode.inputOnly ||
|
||||
_entryMode.value == DatePickerEntryMode.input;
|
||||
// When the portrait dialog does not fit vertically, hide the header when the entry mode
|
||||
// is input, or hide the picker when the entry mode is not input.
|
||||
final bool showHeader = isFullyPortrait || !isInputMode;
|
||||
final bool showPicker = isFullyPortrait || isInputMode;
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
header,
|
||||
if (showHeader) header,
|
||||
if (useMaterial3) Divider(height: 0, color: datePickerTheme.dividerColor),
|
||||
if (isFullyPortrait) ...<Widget>[Expanded(child: picker), actions],
|
||||
if (showPicker) ...<Widget>[Expanded(child: picker), actions],
|
||||
],
|
||||
);
|
||||
case Orientation.landscape:
|
||||
@ -3175,10 +3183,8 @@ class _InputDateRangePickerDialog extends StatelessWidget {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
header,
|
||||
if (isFullyPortrait) ...<Widget>[Expanded(child: picker), actions],
|
||||
],
|
||||
// When the portrait dialog does not fit vertically, hide the header.
|
||||
children: <Widget>[if (isFullyPortrait) header, Expanded(child: picker), actions],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@ -1662,6 +1662,31 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/140311.
|
||||
testWidgets('Text field stays visible when orientation is portrait and height is reduced', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
addTearDown(tester.view.reset);
|
||||
tester.view.physicalSize = const Size(720, 1280);
|
||||
tester.view.devicePixelRatio = 1.0;
|
||||
initialEntryMode = DatePickerEntryMode.input;
|
||||
|
||||
// Text field and header are visible by default.
|
||||
await prepareDatePicker(tester, useMaterial3: true, (Future<DateTime?> range) async {
|
||||
expect(find.byType(TextField), findsOneWidget);
|
||||
expect(find.text('Select date'), findsOne);
|
||||
});
|
||||
|
||||
// Simulate the portait mode on a device with a small display when the virtual
|
||||
// keyboard is visible.
|
||||
tester.view.viewInsets = const FakeViewPadding(bottom: 1000);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Text field is visible and header is hidden.
|
||||
expect(find.byType(TextField), findsOneWidget);
|
||||
expect(find.text('Select date'), findsNothing);
|
||||
});
|
||||
|
||||
// This is a regression test for https://github.com/flutter/flutter/issues/139120.
|
||||
testWidgets('Dialog contents are visible - textScaler 0.88, 1.0, 2.0', (
|
||||
WidgetTester tester,
|
||||
|
||||
@ -1243,6 +1243,31 @@ void main() {
|
||||
expect(tester.takeException(), null);
|
||||
});
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/140311.
|
||||
testWidgets('Text field stays visible when orientation is portrait and height is reduced', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
addTearDown(tester.view.reset);
|
||||
tester.view.physicalSize = const Size(720, 1280);
|
||||
tester.view.devicePixelRatio = 1.0;
|
||||
initialEntryMode = DatePickerEntryMode.input;
|
||||
|
||||
// Text fields and header are visible by default.
|
||||
await preparePicker(tester, useMaterial3: true, (Future<DateTimeRange?> range) async {
|
||||
expect(find.byType(TextField), findsNWidgets(2));
|
||||
expect(find.text('Select range'), findsOne);
|
||||
});
|
||||
|
||||
// Simulate the portait mode on a device with a small display when the virtual
|
||||
// keyboard is visible.
|
||||
tester.view.viewInsets = const FakeViewPadding(bottom: 1000);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Text fields are visible and header is hidden
|
||||
expect(find.byType(TextField), findsNWidgets(2));
|
||||
expect(find.text('Select range'), findsNothing);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('DatePickerDialog is state restorable', (WidgetTester tester) async {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user