Going to result after search with SearchDelegate (buildResults) - flutter

I made a simple search bar with SearchDelegate.
Although there are many resources on the internet about searching, there is almost no source on how to get results when the search is over.
My list, detail page and search bar are in this view
After searching, how can I go to the detail page with the buildResults?
class SearchTeam extends SearchDelegate<String> {
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = "";
})
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
#override
Widget buildResults(BuildContext context) {
// How can I go to the detail page of the found team name?
}
#override
Widget buildSuggestions(BuildContext context) {
final suggestionList = query.isEmpty
? [" "]
: MyData.TEAM_NAME.where((p) => p.toLowerCase().contains(query.toLowerCase()))
.toList();
return ListView.builder(
itemBuilder: (context, index) => ListTile(
onTap: (){},
title: Text(suggestionList[index]),
),
itemCount: suggestionList.length,
);
}
}

You can't take advantage of the keyboard's onSubmitted event when using a SearchDelegate as it won't expose the API to do that. Don't use SearchDelegate just for showing the TextField in that case. If you want to use your custom page for displaying search results, create your own search input TextField as well. It will be easier for you to do that with much better APIs that you can have control over.
If you are to use SearchDelegate you have to build your result widget directly in the buildResults method. In your case, show a widget using the query field which on pressing will take the user to the detail page. Or you can just navigate to the detail page upon pressing the item in the suggested list.
It would be something like this.
List<String> getResults(String query) {
// apply getting results logic here
return [];
}
#override
Widget buildResults(BuildContext context) {
final results = getResults(query);
return ListView.builder(
itemBuilder: (context, index) => ListTile(
onTap: () {
// assuming `DetailsPage` exists
Navigator.push(context, DetailsPage(results[index]));
},
title: Text(results[index]),
),
itemCount: results.length,
);
}

it works,
just ignore the returning value of buildResults()
thank you.

Related

I wants to filter list view as per the search query and there should be pagination used for 1000 documents on same page & all docs should be searched

I am getting data of documents through API. I have tried many ways but couldn't resolved that how to filter the list.
I didn't properly understand your question, but you can use the stream builder.
You get the pages from the api and add them to the stream. Check this link.
https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html
you have to show some of the code you already have so as to know where to start from helping you, but anyways, this is the basic logic to do it,
first, you should have some sort of searchDelegate set up, then in your CustomSearchDelegate you should
class MyDelegate extends SearchDelegate<returnType> {
#override
Widget? buildLeading(BuildContext context) {
return IconButton(
icon: const Icon(Icons.arrow_back), // could be anything
onPressed: () {
Navigator.pop(context); /* could be anything you want your leading icon to do */
},
);
}
#override
List<Widget>? buildActions(BuildContext context) {
return [
IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
query.isEmpty ? Navigator.pop(context) : query = ''; // again, could be anything at all
},
),
];
}
#override
Widget buildResults(BuildContext context) {
return const Center();
}
#override
Widget buildSuggestions(BuildContext context) {
List<dataType> suggestions;
query.isEmpty
? suggestions = [] /* if you want the list to be empty first time user opens searchpage or if user clears search field else, remove the check */
: suggestions = ListfromAPI.where((data) {
final result = data.toLowerCase();
final input = query.toLowerCase();
return result.contains(input);
}).toList();
return ListView.builder(
itemCount: suggestions.length,
itemBuilder: (context, suggestIndex) {
final suggestion = suggestions[suggestIndex];
return ListTile(
title: Text(suggestion),
onTap: () {
close(context, suggestion); /* passing back the data user selected and where you call showSearch(), you await this data and when it arrives, you use it to do anything you want to */
},
);
});
}
}

Navigte back with params in flutter using GetX and accessing the results in the previous page

I am creating a flutter app which enables a user to select a contact and display the selected contact before navigating back from the list of contact.
class ContactsList extends StatelessWidget {
final List<AppContact> contacts;
Function() reloadContacts;
ContactsList({Key? key, required this.contacts, required this.reloadContacts})
: super(key: key);
#override
Widget build(BuildContext context) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: contacts.length,
itemBuilder: (context, index) {
AppContact contact = contacts[index];
return ListTile(
onTap: () {
Get.back(result:contact.info.phones!.elementAt(0).value!);
},
title: Text(contact.info.displayName!),
subtitle: Text(contact.info.phones!.length > 0
? contact.info.phones!.elementAt(0).value!
: ''),
leading: ContactAvatar(contact, 36));
},
),
);
}
}
I'm not sure you want this but, you can just use await keyword with navigate function.
For example;
final data = await Get.to(Payment());
if you want to learn some information about navigation with getx you can visit documentation

How to select only one item in ListView and render it?

I started studying flutter and I'm having a doubt about LsitViewBuilder.
I have this ListView that accesses the JSON data locally by rootBundle, but I would like that when I click on some item it would only open it on the second page.
I wanted so much to know how you can select.
My ListView
List<dynamic> buy;
#override
void initState() {
super.initState();
rootBundle.loadString('assets/dados.json').then((jsonData) {
this.setState(() {
buy = jsonDecode(jsonData);
});
});
}
........
ListView.builder(
itemCount: buy?.length ?? 0,
itemBuilder: (_, index) {
return buildCardBuy(context, index, buy);
}
),
You can wrap your list view item with the GestureDetector widget, making the Tap event to navigate to another page with the item tapped.
ListView.builder(
itemCount: buy?.length ?? 0,
itemBuilder: (_, index) {
return GestureDetector(
child: buildCardBuy(context, index, buy),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
// the first refeers to the property on your detail DetailScreen
// and the second refers to the current buy being render on
// this list view builder
builder: (context) => DetailScreen(buy: buy),
),
);
);
}
),
And in your DetailScreen something like
class DetailScreen extends StatelessWidget {
final dynamic buy;
DetailScreen({Key key, #required this.buy}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
),
body: Container()
);
}
}
I would build a second widget (let's call it ItemWidget) which represents the detail page for the object you want to 'open'.
Then I would add to that ItemWidget a property for the object data that you need to pass.
After that I would implement the logic so that when the list item is clicked, it switches the current list widget with a new ItemWidget and passes to it the properties of the clicked object.

How to store and retrieve a List<Widgets> to achieve persitence

I'm new to UI Programming/ App development.
My goal is it to have a screen/page/whatever on which one can arrange different Widgets.
Of course this "layout" should be saved in some way but I have no clue how.
This is the page on which you can arrange the widgets:
const MyDesign({Key key,this.designName}):super(key: key);
final String designName;
#override
_MyDesignState createState() => _MyDesignState();
}
class _MyDesignState extends State<MyDesign> {
List<Widget> movableItems = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.designName),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
movableItems.add(MoveableStackItem(item: Knob(),));
});
}
),
body: Stack(
children:
movableItems,
),
);
}
}
As you can see I use a List to store my movable objects and a Stack to draw them.
Is there any possibility to store this List of widgets for a specific instance of this page and retrieve it after closing the app?
I also want to have the possibility to create multiple "layouts" heres my approach:
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<MyDesign> myDesignPages = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final String dname = (await _asyncInputDialog(context)) as String;
setState(() {
myDesignPages.add(new MyDesign(designName: dname,));
});
},
child: Icon(Icons.add),
),
body:
new ListView.builder(
itemCount: myDesignPages.length,
itemBuilder: (BuildContext context, int i){
return ListTile(
title: Text(myDesignPages[i].designName),
onTap: () {
Navigator.push<dynamic>(
context,
MaterialPageRoute<dynamic>(
builder: (context) => myDesignPages[i]) );
},
);
}
),
);
}
}
I assume that I'm quite off the track here. For that I'm happy places like this exist.
Thanks a lot
To answer your first question: Yes it's possible to encode and save your list content as a String and to retrieve it later by decoding the saved String. To save String as key value pair you can for example use this plugin Shared preferences. To encode and decode your list you can use respectively jsonEncode and jsonDecode from dart:convert package

Flutter showSearch keyboard search

I am very new to Flutter and Dart so I am trying to build a simple search app with queries based on a word typed in Flutters showSearch search bar. I understand the listtile that is built to show suggestions to the user, and tapping that suggestion will activate the buildresults widget. However, I want to enable the search button on the keyboard to simply search the inputted word, rather than tapping on the limited suggestion list.
Simple android keyboard
When the button is clicked normally, the keyboard is closed the buildresults is not activated. So far you have to actually click a suggested listtile option. Is there a way to enable the keyboard's search button to search the inputted text? or Is the user limited to the suggested listtile options? I will list my showSearch delegate below:
class StockDelegate extends SearchDelegate<String> {
final stocks = [
"IBM",
"NKLAW",
"DKNGZ",
"DRD",
"PRTS",
"TSLA",
"KIRK",
"VBIV"
];
final suggested = ["IBM", "TSLA", "BNTX"];
#override
// TODO: implement textInputAction
// TODO: implement textInputAction
TextInputAction get textInputAction => super.textInputAction;
#override
List<Widget> buildActions(BuildContext context) {
//actions for app bar
StockProvider _stockProvider =
Provider.of<StockProvider>(context, listen: true);
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = '';
}),
];
}
#override
Widget buildLeading(BuildContext context) {
//Leading icon on the left of the app bar
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
#override
Widget buildResults(BuildContext context) {
//build results code
}
#override
Widget buildSuggestions(BuildContext context) {
// show when someone search for something
stocks.insert(0, query.toString());
final suggestionList = query.isEmpty
? suggested
: stocks.where((p) => p.startsWith(query)).toList();
return ListView.builder(
itemCount: suggestionList.length,
itemBuilder: (context, index) => ListTile(
onTap: () async {
Provider.of<StockProvider>(context, listen: false)
.searchBySymbol(suggestionList[index]);
if (!stocks.contains(suggestionList[index]))
suggestionList.add(suggestionList[index]);
showResults(context);
},
leading: Icon(Icons.attach_money),
title: Text(suggestionList[index]),
),
);
}
I don't know whether you know about onSubmitted property or not, which is used in the TextField/Text/TextFormField. Since, I cannot see your TexFormField/Text/TextField anywhere, but I think you must be using it somewhere.
So, this is how onFieldSubmitted used, which does the job which you want, that is, when the user hit on the magnifying lens on the keypad, it runs your function
TextFormField(
controller: _yourTextEditingController,
textInputAction: TextInputAction.search,
onFieldSubmitted: (){
// here you do your operation when you hit the
// keypad magnifying lens
// check with print()
print('Pressed via keypad');
}
)
Don't get confused with onSubmitted name, onFieldSubmitted is used in TextFormField/Text/TextField, which uses onSubmitted property. I hope that answers your question :) Let me know, is that was the thing you were looking for.
Override showResults() method similar to buildSuggestions().
override showResults method as follow:
#override
void showResults(BuildContext context) {
super.showResults(context);
showSuggestions(context);
FocusScope.of(context).unfocus();
}