in this code a have a search function but when ever I search for apple its shows me apple a few times instead of only once
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key key, @required this.title}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
//Search TextField Controller
final _searchController = TextEditingController();
List<Fruit> mainList = [
Fruit(name: 'Apple', imageUrl: 'https://images.pexels.com/photos/102104/pexels-photo-102104.jpeg'),
Fruit(name: 'Banana', imageUrl: 'https://images.pexels.com/photos/5945848/pexels-photo-5945848.jpeg'),
Fruit(name: 'Pineapple', imageUrl: 'https://images.pexels.com/photos/1071878/pexels-photo-1071878.jpeg'),
Fruit(name: 'Mango', imageUrl: 'https://images.pexels.com/photos/918643/pexels-photo-918643.jpeg'),
];
List<Fruit> searchList = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
height: 60.0,
child: TextFormField(
controller: _searchController,
onChanged: (text){
final String queryString = _searchController.text;
setState((){
if(queryString.isNotEmpty){
for(final fruit in mainList){
if(fruit.name.contains(queryString)){
searchList.add(fruit);
} else{
searchList.remove(fruit);
}
}
}else{
searchList.clear();
}
});
}
),
),
Expanded(
child: _searchController.text.isEmpty
? GridView.count(
crossAxisCount: 2,
children: mainList.map((fruit)=> CardWidget(fruit: fruit)).toList(),
)
:GridView.count(
crossAxisCount: 2,
children: searchList.map((searchedFruit)=>CardWidget(fruit: searchedFruit)).toList()
),
),
],
),
);
}
}
I think that the main problem here is with the searchList, It just add the same fruit over and over.
Class to hold Fruit
class Fruit{
final String imageUrl;
final String name;
Fruit({this.imageUrl, this.name});
}
widget to be built for each fruit object found in the mainList
//Card Widget
class CardWidget extends StatefulWidget{
final Fruit fruit;
CardWidget({this.fruit});
@override
_CardWidgetState createState()=> _CardWidgetState();
}
class _CardWidgetState extends State<CardWidget>{
@override
Widget build(BuildContext context){
return Container(
width: 100.0,
height: 140.0,
child: Column(
children:[
Image(image: NetworkImage(widget.fruit.imageUrl)),
SizedBox(height: 10.0),
Text(widget.fruit.name),
]
)
);
}
}
CodePudding user response:
Ok, I believe the problem is every time you enter a new character the code will search and add to the search list, but you have to reset the list for each search otherwise the list will have repeated characters. Here's how to do it:
onChanged: (text){
final String queryString = _searchController.text;
setState((){
if(queryString.isNotEmpty){
searchList.clear(); // clear the list before the search loop
for(final fruit in mainList){
if(fruit.name.contains(queryString)){
searchList.add(fruit);
} else{
searchList.remove(fruit);
}
}
}else{
searchList.clear();
}
}
CodePudding user response:
try this..
initialize debounce below the TextEditingController
final _searchController = TextEditingController();
final _deBouncer = Debouncer(millisecound: 400);
replace onChanged function
onChanged: (text) async {
searchList.clear();
await _deBouncer.run(() {
final String queryString = text;
if (queryString.isNotEmpty) {
for (final fruit in mainList) {
if
(fruit.name?.toLowerCase().contains(queryString.toLowerCase()) ??
false) {
searchList.add(fruit);
}
}
}
setState(() {});
});
}),
add this class for when user stop to typing in search text field
class Debouncer {
final int? millisecound;
VoidCallback? action;
Timer? _timer;
Debouncer({this.millisecound});
run(VoidCallback action) {
if (_timer != null) {
_timer?.cancel();
}
_timer = Timer(Duration(milliseconds: millisecound ?? 300), action);
}
}