Skip to content

Instantly share code, notes, and snippets.

@guptahitesh121
Created May 1, 2020 13:29
Show Gist options
  • Save guptahitesh121/f505f811151145b6d61824d509b28483 to your computer and use it in GitHub Desktop.
Save guptahitesh121/f505f811151145b6d61824d509b28483 to your computer and use it in GitHub Desktop.
typedef Future<List<String>> OnChanged(String text);
class TypeAheadTextField extends StatefulWidget {
final OnChanged onChanged;
final ValueChanged onSelect;
TypeAheadTextField({this.onChanged, this.onSelect});
@override
_TypeAheadTextFieldState createState() => _TypeAheadTextFieldState();
}
class _TypeAheadTextFieldState extends State<TypeAheadTextField> {
final TextEditingController _controller = TextEditingController();
final LayerLink _layerLink = LayerLink();
final FocusNode _focusNode = FocusNode();
OverlayEntry _overlayEntry;
Timer _pending;
String _previousText;
@override
void initState() {
super.initState();
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
_controller.addListener(_onTextChanged);
} else {
_controller.removeListener(_onTextChanged);
}
});
}
void _onTextChanged() {
final currentText = _controller.text;
if (_overlayEntry != null) {
_overlayEntry.remove();
_overlayEntry = null;
}
if (isBlank(currentText) || _previousText == currentText) {
_previousText = currentText;
return;
}
_previousText = currentText;
if (_pending != null && _pending.isActive) {
_pending.cancel();
}
_pending = Timer(Duration(milliseconds: 500), () async {
this._overlayEntry = this._createOverlayEntry(null);
Overlay.of(context).insert(this._overlayEntry);
final items = await widget?.onChanged?.call(currentText);
if (_previousText == currentText) {
_overlayEntry.remove();
_overlayEntry = null;
if (isListNotEmpty(items)) {
this._overlayEntry = this._createOverlayEntry(items);
Overlay.of(context).insert(this._overlayEntry);
}
}
});
}
OverlayEntry _createOverlayEntry(List<String> items) {
RenderBox renderBox = context.findRenderObject();
var size = renderBox.size;
return OverlayEntry(
builder: (context) => Positioned(
width: size.width,
child: CompositedTransformFollower(
link: this._layerLink,
showWhenUnlinked: false,
offset: Offset(0.0, size.height),
child: Material(
elevation: 4.0,
child: items == null
? ConstrainedBox(
constraints: BoxConstraints(maxHeight: 60),
child: ShimmerLoading(),
)
: ConstrainedBox(
constraints: BoxConstraints(maxHeight: 350),
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: items?.length ?? 0,
itemBuilder: (c, i) {
final item = items[i];
return ListTile(
title: PText(item),
onTap: () {
if (_overlayEntry != null) {
_overlayEntry.remove();
_overlayEntry = null;
}
_controller.text = item;
widget.onSelect(item);
},
);
},
),
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: this._layerLink,
child: mFormTextField1(
focusNode: _focusNode,
hint: "Search Here",
controller: _controller,
validator: (String v) {
if (isBlank(v)) {
return "enter your search ";
}
return null;
},
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment