I am using an overlay entry which contains a listviewbuilder. Now that list is being filtered when user give an input. the issue is that when I filtered the list without overlay it works fine but when I user overlay the list is not filtered on input. it is filtered when i remove a value from user input. Like I entered Dorm-G-01 but it will not show results of it if I remove 1 from it then it gives the result of Dorm-G-01. According to me setState is not changing upon input.
`
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class Address extends StatefulWidget {
@override
_AddressState createState() => _AddressState();
}
class _AddressState extends State<Address> {
final FocusNode _focusNode = FocusNode();
TextEditingController addressController = TextEditingController();
late OverlayEntry _overlayEntry;
List<String> _hostel = [];
List<String> _filter = [];
String serachText="";
Timer? _debounce;
final LayerLink _layerLink = LayerLink();
void getAddress() {
final Stream<QuerySnapshot> _usersStream =
FirebaseFirestore.instance.collection('Services').snapshots();
}
@override
void initState() {
_hostel.add('Dorm-G-01');
_hostel.add('Dorm-G-02');
_hostel.add('Dorm-G-03');
_hostel.add('Dorm-G-04');
_hostel.add('Dorm-G-05');
_hostel.add('Dorm-G-06');
_hostel.add('Dorm-G-07');
// _filter = _hostel;
addressController.addListener(_onSerachChanged);
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
this._overlayEntry = this._createOverlayEntry();
Overlay.of(context)!.insert(this._overlayEntry);
} else {
this._overlayEntry.remove();
}
});
}
OverlayEntry _createOverlayEntry() {
final renderBox = context.findRenderObject() as RenderBox;
var size = renderBox.size;
final offset = renderBox.localToGlobal(Offset.zero);
return OverlayEntry(
builder: (context) => Positioned(
left: offset.dx,
top: offset.dy,
bottom: offset.dy,
width: size.width,
child: CompositedTransformFollower(
link: this._layerLink,
showWhenUnlinked: false,
offset: Offset(0.0, size.height + 5.0),
child: Material(
elevation: 4.0,
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: _filter.length,
shrinkWrap: true,
physics: AlwaysScrollableScrollPhysics(),
itemBuilder: (context, index) {
return ListTile(
tileColor: Colors.grey.shade300,
title: Text(_filter[index].toString()),
onTap: () {
setState(() {
addressController.text = _filter[index];
_focusNode.unfocus();
});
},
);
}),
),
),
));
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: this._layerLink,
child: TextFormField(
controller: addressController,
focusNode: this._focusNode,
decoration: InputDecoration(labelText: 'Address'),
),
);
}
//on serach changed
_onSerachChanged() {
if(_debounce?.isActive ?? false) _debounce!.cancel();
_debounce = Timer(
const Duration(milliseconds: 100),
() {
_filter = _hostel;
setState(() {
_filter=_filter
.where((item) => item
.toString()
.replaceAll(RegExp(r'[^\w\\s]+'), '')
.toLowerCase()
.contains(addressController.text
.toString()
.replaceAll(RegExp(r'[^\w\\s]+'), '')
.toLowerCase()))
.toList();
});
},
);
} //onSerachChanged
@override
void dispose() {
addressController.removeListener(_onSerachChanged);
addressController.dispose();
_debounce!.cancel();
super.dispose();
}
}
`
Solution 1: Zia Ur Rehman
I was able to fix this issue by just passing the filtration method inside textformfiled->onchanged
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: this._layerLink,
child: TextFormField(
controller: addressController,
focusNode: this._focusNode,
decoration: InputDecoration(labelText: 'Address'),
onChanged: (value) {
setState(() {
_filter = _hostel.where((hostel) => hostel.toLowerCase().replaceAll(RegExp(r'[^\w\\s]+'), '').contains(value.toLowerCase().replaceAll(RegExp(r'[^\w\\s]+'), ''))).toList();
});
},
),
);
}