Я пытаюсь создать текстовое поле с автозаполнением, которое решает, отображать ли список предложений вверх или вниз относительно текстового поля в зависимости от того, где на экране больше места. Например:
AutocompleteTextFieldExample
Чтобы решить, в каком направлении визуализировать его, мне нужно знать, сколько места покрыто клавиатурой, поэтому я использую: "MediaQuery.of (context) .viewPadding.bottom "
Однако" MediaQuery.of (context) .viewPadding.bottom "всегда возвращает 0.0, если я установил resizeToAvoidBottomInset: true. Поэтому мне нужно установить его в ложь. Но при этом текстовые поля при фокусировке покрываются клавиатурой, как вы можете видеть на этих двух изображениях:
Экран
Экран с фокусировкой на нижнее текстовое поле
Пока это мой textFieldCode:
class _AutoCompleteTextFieldState extends State<AutoCompleteTextField> {
final double _maxSuggestionBoxDimension = 300;
OverlayEntry _overlayEntry;
final LayerLink _layerLink = LayerLink();
final FocusNode _focusNode = FocusNode();
final TextEditingController _textEditingController =
new TextEditingController();
// it contains the listTiles utilized by the overlay
// the items are changed inside the
List<ListTile> listTiles = [];
@override
void initState() {
super.initState();
// it inserts or remove the suggestions container depending on the focus of the textfield
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
this._overlayEntry = this._createOverlayEntry();
Overlay.of(context).insert(this._overlayEntry);
} else {
this._overlayEntry.remove();
}
});
// if text is not empty it updates the suggestion in the suggestions box
_textEditingController.addListener(() {
// move this logic inside updateSuggestinoContainer
if (_textEditingController.text.isNotEmpty) {
updateSuggestionContainer(_textEditingController.text);
} else {
listTiles = [];
_overlayEntry.markNeedsBuild();
}
});
}
// it modify the suggestion container depending on the input text (in the textfield),
// it works in 3 part
// - defining the List of string which rappresent the suggestions that will be in the suggestions container
// - create and assign the new List of ListTile that will be used to build the suggestions container
// - mark _overlayEntry as dirty to rebuild and
void updateSuggestionContainer(String text) {
List<String> stringSuggestions = getStringSuggestions(text);
listTiles = getListTileSuggestion(stringSuggestions);
_overlayEntry.markNeedsBuild();
}
// it defines what suggestion to visualize
List<String> getStringSuggestions(String text) {
return widget.suggestions
.where((possibleSuggestion) =>
possibleSuggestion.substring(0, text.length) == text)
.toList();
}
// it define how to visualize each single suggestion
List<ListTile> getListTileSuggestion(List<String> suggestions) {
List<ListTile> listTiles = [];
for (String suggestion in suggestions) {
listTiles.add(ListTile(title: Text(suggestion)));
}
return listTiles;
}
OverlayEntry _createOverlayEntry() {
RenderBox renderBox = context.findRenderObject();
var size = renderBox.size;
Offset position = renderBox.localToGlobal(Offset.zero);
Future.delayed(Duration(seconds: 3)).then((_) {
print("${_showBottom(position.dy)}");
});
return OverlayEntry(
builder: (context) => Positioned(
width: size.width,
child: CompositedTransformFollower(
link: this._layerLink,
showWhenUnlinked: false,
offset: Offset(
0.0,
_showBottom(position.dy)
? min(size.height + 5.0, _maxSuggestionBoxDimension)
: max(-listTiles.length * 56.0 - size.height + 40.0,
-_maxSuggestionBoxDimension)),
child: Material(
child: Container(
height: min(
listTiles.length * 56.0, _maxSuggestionBoxDimension),
//duration: Duration(milliseconds: 150),
color: Colors.white,
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: ListView(
reverse: _showBottom(position.dy) ? false : true,
children: listTiles.isNotEmpty
? ListTile.divideTiles(
context: context, tiles: listTiles)
.toList()
: List()),
),
),
),
),
));
}
// controll whetever the suggestion should be shown above or bottom the textField
bool _showBottom(double textFieldCordinateY) {
print("textFieldCordinateY = $textFieldCordinateY");
print(
"MediaQuery.of(context).size.height = ${MediaQuery.of(context).size.height}");
print(
"MediaQuery.of(context).viewInsets.bottom = ${MediaQuery.of(context).viewInsets.bottom}");
print(
"MediaQuery.of(context).viewPadding.bottom = ${MediaQuery.of(context).viewPadding.bottom}");
// TODO
// consider also the top viewInsets
if ((MediaQuery.of(context).size.height -
MediaQuery.of(context).viewInsets.bottom) /
2 >
textFieldCordinateY)
return true;
else
return false;
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: this._layerLink,
child: TextFormField(
//scrollPadding: EdgeInsets.all(500),
controller: _textEditingController,
focusNode: this._focusNode,
decoration: InputDecoration(suffixIcon: Icon(Icons.arrow_drop_down)),
),
);
}
}
Это код сборки моего экрана:
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(title: Text("Titolo")),
body: ListView(children: [
SizedBox(height: 15),
Container(
padding: EdgeInsets.all(20),
child: AutoCompleteTextField(["Ape", "Areoplano", "Austronauta"])),
SizedBox(height: 200),
Container(
padding: EdgeInsets.all(20),
child: AutoCompleteTextField([
"Biliardo",
"Bufu",
"Bamba",
"Bici",
"Bambolina",
"Busta",
"Bella",
"Basta",
"Balza"
])),
SizedBox(height: 200),
Container(
padding: EdgeInsets.all(20),
child: AutoCompleteTextField(["Ciru", "Capanna", "Casa"]),
),
]),
);
}
Заранее спасибо .