[a11y] Fix date picker cannot focus on the edit field (#143117)
fixes: [DatePicker edit field](https://github.com/flutter/flutter/issues/143116) https://b.corp.google.com/issues/322173632
This commit is contained in:
parent
3f09b23338
commit
846719ecaf
@ -394,6 +394,7 @@ class _DatePickerModeToggleButtonState extends State<_DatePickerModeToggleButton
|
|||||||
label: MaterialLocalizations.of(context).selectYearSemanticsLabel,
|
label: MaterialLocalizations.of(context).selectYearSemanticsLabel,
|
||||||
excludeSemantics: true,
|
excludeSemantics: true,
|
||||||
button: true,
|
button: true,
|
||||||
|
container: true,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: _subHeaderHeight,
|
height: _subHeaderHeight,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
|
@ -867,64 +867,76 @@ class _DatePickerHeader extends StatelessWidget {
|
|||||||
|
|
||||||
switch (orientation) {
|
switch (orientation) {
|
||||||
case Orientation.portrait:
|
case Orientation.portrait:
|
||||||
return SizedBox(
|
return Semantics(
|
||||||
height: _datePickerHeaderPortraitHeight,
|
container: true,
|
||||||
child: Material(
|
child: SizedBox(
|
||||||
color: backgroundColor,
|
height: _datePickerHeaderPortraitHeight,
|
||||||
child: Padding(
|
child: Material(
|
||||||
padding: const EdgeInsetsDirectional.only(
|
color: backgroundColor,
|
||||||
start: 24,
|
child: Padding(
|
||||||
end: 12,
|
padding: const EdgeInsetsDirectional.only(
|
||||||
bottom: 12,
|
start: 24,
|
||||||
),
|
end: 12,
|
||||||
child: Column(
|
bottom: 12,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
),
|
||||||
children: <Widget>[
|
child: Column(
|
||||||
const SizedBox(height: 16),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
help,
|
children: <Widget>[
|
||||||
const Flexible(child: SizedBox(height: 38)),
|
const SizedBox(height: 16),
|
||||||
Row(
|
help,
|
||||||
children: <Widget>[
|
const Flexible(child: SizedBox(height: 38)),
|
||||||
Expanded(child: title),
|
Row(
|
||||||
if (entryModeButton != null)
|
children: <Widget>[
|
||||||
entryModeButton!,
|
Expanded(child: title),
|
||||||
],
|
if (entryModeButton != null)
|
||||||
),
|
Semantics(
|
||||||
],
|
container: true,
|
||||||
|
child: entryModeButton,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
case Orientation.landscape:
|
case Orientation.landscape:
|
||||||
return SizedBox(
|
return Semantics(
|
||||||
width: _datePickerHeaderLandscapeWidth,
|
container: true,
|
||||||
child: Material(
|
child:SizedBox(
|
||||||
color: backgroundColor,
|
width: _datePickerHeaderLandscapeWidth,
|
||||||
child: Column(
|
child: Material(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
color: backgroundColor,
|
||||||
children: <Widget>[
|
child: Column(
|
||||||
const SizedBox(height: 16),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Padding(
|
children: <Widget>[
|
||||||
padding: const EdgeInsets.symmetric(
|
const SizedBox(height: 16),
|
||||||
horizontal: _headerPaddingLandscape,
|
Padding(
|
||||||
),
|
|
||||||
child: help,
|
|
||||||
),
|
|
||||||
SizedBox(height: isShort ? 16 : 56),
|
|
||||||
Expanded(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: _headerPaddingLandscape,
|
horizontal: _headerPaddingLandscape,
|
||||||
),
|
),
|
||||||
child: title,
|
child: help,
|
||||||
),
|
),
|
||||||
),
|
SizedBox(height: isShort ? 16 : 56),
|
||||||
if (entryModeButton != null)
|
Expanded(
|
||||||
Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
padding: const EdgeInsets.symmetric(
|
||||||
child: entryModeButton,
|
horizontal: _headerPaddingLandscape,
|
||||||
|
),
|
||||||
|
child: title,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
if (entryModeButton != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
child: Semantics(
|
||||||
|
container: true,
|
||||||
|
child: entryModeButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -256,21 +256,25 @@ class _InputDatePickerFormFieldState extends State<InputDatePickerFormField> {
|
|||||||
?? theme.inputDecorationTheme.border
|
?? theme.inputDecorationTheme.border
|
||||||
?? (useMaterial3 ? const OutlineInputBorder() : const UnderlineInputBorder());
|
?? (useMaterial3 ? const OutlineInputBorder() : const UnderlineInputBorder());
|
||||||
|
|
||||||
return TextFormField(
|
return Semantics(
|
||||||
decoration: InputDecoration(
|
container: true,
|
||||||
hintText: widget.fieldHintText ?? localizations.dateHelpText,
|
child: TextFormField(
|
||||||
labelText: widget.fieldLabelText ?? localizations.dateInputLabel,
|
decoration: InputDecoration(
|
||||||
).applyDefaults(inputTheme
|
hintText: widget.fieldHintText ?? localizations.dateHelpText,
|
||||||
.merge(datePickerTheme.inputDecorationTheme)
|
labelText: widget.fieldLabelText ?? localizations.dateInputLabel,
|
||||||
.copyWith(border: effectiveInputBorder),
|
).applyDefaults(
|
||||||
|
inputTheme
|
||||||
|
.merge(datePickerTheme.inputDecorationTheme)
|
||||||
|
.copyWith(border: effectiveInputBorder),
|
||||||
|
),
|
||||||
|
validator: _validateDate,
|
||||||
|
keyboardType: widget.keyboardType ?? TextInputType.datetime,
|
||||||
|
onSaved: _handleSaved,
|
||||||
|
onFieldSubmitted: _handleSubmitted,
|
||||||
|
autofocus: widget.autofocus,
|
||||||
|
controller: _controller,
|
||||||
|
focusNode: widget.focusNode,
|
||||||
),
|
),
|
||||||
validator: _validateDate,
|
|
||||||
keyboardType: widget.keyboardType ?? TextInputType.datetime,
|
|
||||||
onSaved: _handleSaved,
|
|
||||||
onFieldSubmitted: _handleSubmitted,
|
|
||||||
autofocus: widget.autofocus,
|
|
||||||
controller: _controller,
|
|
||||||
focusNode: widget.focusNode,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import '../widgets/clipboard_utils.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
@ -1577,6 +1578,13 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('input mode', (WidgetTester tester) async {
|
testWidgets('input mode', (WidgetTester tester) async {
|
||||||
|
// Fill the clipboard so that the Paste option is available in the text
|
||||||
|
// selection menu.
|
||||||
|
final MockClipboard mockClipboard = MockClipboard();
|
||||||
|
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
|
||||||
|
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
|
||||||
|
addTearDown(() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null));
|
||||||
|
|
||||||
final SemanticsHandle semantics = tester.ensureSemantics();
|
final SemanticsHandle semantics = tester.ensureSemantics();
|
||||||
|
|
||||||
initialEntryMode = DatePickerEntryMode.input;
|
initialEntryMode = DatePickerEntryMode.input;
|
||||||
@ -1596,7 +1604,20 @@ void main() {
|
|||||||
isFocusable: true,
|
isFocusable: true,
|
||||||
));
|
));
|
||||||
|
|
||||||
// The semantics of the InputDatePickerFormField are tested in its tests.
|
expect(tester.getSemantics(find.byType(EditableText)), matchesSemantics(
|
||||||
|
label: 'Enter Date',
|
||||||
|
isTextField: true,
|
||||||
|
isFocused: true,
|
||||||
|
value: '01/15/2016',
|
||||||
|
hasTapAction: true,
|
||||||
|
hasSetTextAction: true,
|
||||||
|
hasSetSelectionAction: true,
|
||||||
|
hasCopyAction: true,
|
||||||
|
hasCutAction: true,
|
||||||
|
hasPasteAction: true,
|
||||||
|
hasMoveCursorBackwardByCharacterAction: true,
|
||||||
|
hasMoveCursorBackwardByWordAction: true,
|
||||||
|
));
|
||||||
|
|
||||||
// Ok/Cancel buttons
|
// Ok/Cancel buttons
|
||||||
expect(tester.getSemantics(find.text('OK')), matchesSemantics(
|
expect(tester.getSemantics(find.text('OK')), matchesSemantics(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user