Unverified Commit 69b92f04 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

Hide autocomplete menu on select. (#100251)

parent ef912b8d
......@@ -316,6 +316,7 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
_userHidOptions = false;
_lastFieldText = value.text;
}
_updateActions();
_updateOverlay();
}
......@@ -323,6 +324,7 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
void _onChangedFocus() {
// Options should no longer be hidden when the field is re-focused.
_userHidOptions = !_focusNode.hasFocus;
_updateActions();
_updateOverlay();
}
......@@ -345,6 +347,8 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
selection: TextSelection.collapsed(offset: selectionString.length),
text: selectionString,
);
_updateActions();
_updateOverlay();
widget.onSelected?.call(_selection!);
}
......@@ -355,6 +359,7 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
void _highlightPreviousOption(AutocompletePreviousOptionIntent intent) {
if (_userHidOptions) {
_userHidOptions = false;
_updateActions();
_updateOverlay();
return;
}
......@@ -364,6 +369,7 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
void _highlightNextOption(AutocompleteNextOptionIntent intent) {
if (_userHidOptions) {
_userHidOptions = false;
_updateActions();
_updateOverlay();
return;
}
......@@ -373,6 +379,7 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
Object? _hideOptions(DismissIntent intent) {
if (!_userHidOptions) {
_userHidOptions = true;
_updateActions();
_updateOverlay();
return null;
}
......@@ -389,12 +396,27 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
_hideOptionsAction.enabled = enabled;
}
void _updateActions() {
_setActionsEnabled(_focusNode.hasFocus && _selection == null && _options.isNotEmpty);
}
bool _floatingOptionsUpdateScheduled = false;
// Hide or show the options overlay, if needed.
void _updateOverlay() {
_setActionsEnabled(_focusNode.hasFocus && _selection == null && _options.isNotEmpty);
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
if (!_floatingOptionsUpdateScheduled) {
_floatingOptionsUpdateScheduled = true;
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
_floatingOptionsUpdateScheduled = false;
_updateOverlay();
});
}
return;
}
_floatingOptions?.remove();
if (_shouldShowOptions) {
_floatingOptions?.remove();
_floatingOptions = OverlayEntry(
final OverlayEntry newFloatingOptions = OverlayEntry(
builder: (BuildContext context) {
return CompositedTransformFollower(
link: _optionsLayerLink,
......@@ -411,9 +433,9 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
);
},
);
Overlay.of(context, rootOverlay: true)!.insert(_floatingOptions!);
} else if (_floatingOptions != null) {
_floatingOptions!.remove();
Overlay.of(context, rootOverlay: true)!.insert(newFloatingOptions);
_floatingOptions = newFloatingOptions;
} else {
_floatingOptions = null;
}
}
......@@ -473,9 +495,8 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
AutocompleteNextOptionIntent: _nextOptionAction,
DismissIntent: _hideOptionsAction,
};
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_updateOverlay();
});
_updateActions();
_updateOverlay();
}
@override
......@@ -486,9 +507,8 @@ class _RawAutocompleteState<T extends Object> extends State<RawAutocomplete<T>>
widget.textEditingController,
);
_updateFocusNode(oldWidget.focusNode, widget.focusNode);
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_updateOverlay();
});
_updateActions();
_updateOverlay();
}
@override
......
......@@ -1023,4 +1023,53 @@ void main() {
expect(lastHighlighted, 5);
});
testWidgets('floating menu goes away on select', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/99749.
final GlobalKey fieldKey = GlobalKey();
final GlobalKey optionsKey = GlobalKey();
late AutocompleteOnSelected<String> lastOnSelected;
late FocusNode focusNode;
late TextEditingController textEditingController;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: RawAutocomplete<String>(
optionsBuilder: (TextEditingValue textEditingValue) {
return kOptions.where((String option) {
return option.contains(textEditingValue.text.toLowerCase());
});
},
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
focusNode = fieldFocusNode;
textEditingController = fieldTextEditingController;
return TextField(
key: fieldKey,
focusNode: focusNode,
controller: textEditingController,
);
},
optionsViewBuilder: (BuildContext context, AutocompleteOnSelected<String> onSelected, Iterable<String> options) {
lastOnSelected = onSelected;
return Container(key: optionsKey);
},
),
),
),
);
// The field is always rendered, but the options are not unless needed.
expect(find.byKey(fieldKey), findsOneWidget);
expect(find.byKey(optionsKey), findsNothing);
await tester.enterText(find.byKey(fieldKey), kOptions[0]);
await tester.pumpAndSettle();
expect(find.byKey(optionsKey), findsOneWidget);
// Pretend that the only option is selected. This does not change the
// text in the text field.
lastOnSelected(kOptions[0]);
await tester.pump();
expect(find.byKey(optionsKey), findsNothing);
});
}
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