Created
May 1, 2020 13:29
-
-
Save guptahitesh121/f505f811151145b6d61824d509b28483 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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