var userDetails = {};
var i;
List returnTicketDetails = [] ;
body: new Column(
children: <Widget>[
new Container(
color: Theme.of(context).primaryColor,
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: new Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
// onChanged: onSearchTextChanged,
),
trailing: new IconButton(icon: new Icon(Icons.cancel), onPressed: () {
controller.clear();
// onSearchTextChanged('');
},),
),
new Expanded(
child: userDetails.length != 0 || controller.text.isNotEmpty
? new ListView.builder(
itemCount: userDetails.length,
itemBuilder: (context, i) {
return new Card(
child: new Column
(mainAxisSize: MainAxisSize.min, children:
<Widget>[
new Row(children: <Widget>[
new Container(
width: 80.0,
height: 80.0,
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: new DecorationImage(
fit: BoxFit.fill,
image: new NetworkImage(
"https:..")
)
)),
new Text(userDetails[returnTicketDetails[i]["user_id"]]["first_name"]
),),
,),
new Text(userDetails[returnTicketDetails[i]["user_id"]]["last_name"]),
);
},
)
: new ListView.builder(
itemCount: userDetails.length,
itemBuilder: (context, i) {
return new Card(
child: new ListTile(
//title: new Text(userDetails[returnTicketDetails[i]["user_id"]]["first_name"]),
),
margin: const EdgeInsets.all(0.0),
);
);
}
_getTicketDetails() async {
final response = await http.get(
"https..", headers: {
HttpHeaders.AUTHORIZATION: access_token
});
returnTicketDetails = json.decode(response.body);
for ( i = 0; i < (returnTicketDetails?.length ?? 0); i++) {
final ticketresponse = await http.get(
"https...", headers: {
HttpHeaders.AUTHORIZATION:
access_token
});
userDetails[returnTicketDetails[i]["user_id"]] =
json.decode(ticketresponse.body);
}
}
我几乎所有的东西都按照我想要的方式,但是我想知道如何使搜索功能根据我的ListView的索引工作?所以,例如,如果我输入一个&#34; z&#34;根据我的情况,我不应该在列表中显示任何内容。 我还在这里更新并发布了函数_getTicketDeatils。 提前谢谢!
答案 0 :(得分:18)
我已经根据需要从url获取数据替换了硬编码模型输入。
import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() => runApp(new MaterialApp(
home: new HomePage(),
debugShowCheckedModeBanner: false,
));
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController controller = new TextEditingController();
// Get json result and convert it to model. Then add
Future<Null> getUserDetails() async {
final response = await http.get(url);
final responseJson = json.decode(response.body);
setState(() {
for (Map user in responseJson) {
_userDetails.add(UserDetails.fromJson(user));
}
});
}
@override
void initState() {
super.initState();
getUserDetails();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Home'),
elevation: 0.0,
),
body: new Column(
children: <Widget>[
new Container(
color: Theme.of(context).primaryColor,
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: new Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: onSearchTextChanged,
),
trailing: new IconButton(icon: new Icon(Icons.cancel), onPressed: () {
controller.clear();
onSearchTextChanged('');
},),
),
),
),
),
new Expanded(
child: _searchResult.length != 0 || controller.text.isNotEmpty
? new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, i) {
return new Card(
child: new ListTile(
leading: new CircleAvatar(backgroundImage: new NetworkImage(_searchResult[i].profileUrl,),),
title: new Text(_searchResult[i].firstName + ' ' + _searchResult[i].lastName),
),
margin: const EdgeInsets.all(0.0),
);
},
)
: new ListView.builder(
itemCount: _userDetails.length,
itemBuilder: (context, index) {
return new Card(
child: new ListTile(
leading: new CircleAvatar(backgroundImage: new NetworkImage(_userDetails[index].profileUrl,),),
title: new Text(_userDetails[index].firstName + ' ' + _userDetails[index].lastName),
),
margin: const EdgeInsets.all(0.0),
);
},
),
),
],
),
);
}
onSearchTextChanged(String text) async {
_searchResult.clear();
if (text.isEmpty) {
setState(() {});
return;
}
_userDetails.forEach((userDetail) {
if (userDetail.firstName.contains(text) || userDetail.lastName.contains(text))
_searchResult.add(userDetail);
});
setState(() {});
}
}
List<UserDetails> _searchResult = [];
List<UserDetails> _userDetails = [];
final String url = 'https://jsonplaceholder.typicode.com/users';
class UserDetails {
final int id;
final String firstName, lastName, profileUrl;
UserDetails({this.id, this.firstName, this.lastName, this.profileUrl = 'https://i.amz.mshcdn.com/3NbrfEiECotKyhcUhgPJHbrL7zM=/950x534/filters:quality(90)/2014%2F06%2F02%2Fc0%2Fzuckheadsho.a33d0.jpg'});
factory UserDetails.fromJson(Map<String, dynamic> json) {
return new UserDetails(
id: json['id'],
firstName: json['name'],
lastName: json['username'],
);
}
}
答案 1 :(得分:9)
我会向您推荐这篇search as you type媒体,该文章使用流实现了搜索,基本思路是这样
1. get your data store in a list(in initstate to use this list later in step 5)
2. search for your query in above list (ontext changed in query)
3. store the filtered result (from above search) in a new list
4. add the filtered list to a streams (to show updated result in UI using streambuilder)
5. if searchquery is empty add the datastore list to stream (to show complete data in UI)
图片的下半部分显示了示例实现
如果您希望上面的文章适合您,这就是上述实现过程的输出。
答案 2 :(得分:3)
SearchDelegate
:完整解决方案:
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String _result;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Search')),
body: Center(
child: Column(
children: <Widget>[
Text(_result ?? '', style: TextStyle(fontSize: 18)),
RaisedButton(
onPressed: () async {
var result = await showSearch<String>(
context: context,
delegate: CustomDelegate(),
);
setState(() => _result = result);
},
child: Text('Search'),
),
],
),
),
);
}
}
class CustomDelegate<T> extends SearchDelegate<T> {
List<String> data = nouns.take(100).toList();
@override
List<Widget> buildActions(BuildContext context) => [IconButton(icon: Icon(Icons.clear), onPressed: () => query = '')];
@override
Widget buildLeading(BuildContext context) => IconButton(icon: Icon(Icons.chevron_left), onPressed: () => close(context, null));
@override
Widget buildResults(BuildContext context) => Container();
@override
Widget buildSuggestions(BuildContext context) {
List listToShow;
if (query.isNotEmpty) listToShow = data.where((e) => e.contains(query) && e.startsWith(query)).toList();
else listToShow = data;
return ListView.builder(
itemCount: listToShow.length,
itemBuilder: (_, i) {
return ListTile(
title: Text(listToShow[i]),
onTap: () => close(context, listToShow[i]),
);
},
);
}
}
答案 3 :(得分:2)
参考 Vinoth Kumar 的答案,请注意.contains()
是区分大小写的。因此,要用尽所有匹配项,可以将字符串转换为小写:
_userDetails.forEach((userDetail) {
if (userDetail.firstName.toLowerCase().contains(text.toLowerCase()) || userDetail.lastName.toLowerCase().contains(text.toLowerCase()))
_searchResult.add(userDetail);
});
对我来说很完美。
答案 4 :(得分:1)
在Flutter中,我们必须使用自定义过滤器小部件进行管理,并且必须比较两个不同的对象列表。如
if (country.name.toLowerCase().contains(searchQuery) ||
country.name.contains(searchQuery)) {
filteredRecored.add(country);
}
我找到了示例here
答案 5 :(得分:0)
我正在学习Flutter,正在寻找@Vinoth Kumar示例可完美完成的可搜索列表。
我已将代码拆分为不同的文件,并将HomePage主体简化为几种方法,以使其对我自己更具可维护性/可读性,我认为值得分享。
import 'package:flutter/material.dart';
import 'homepage.dart';
void main() => runApp(new MaterialApp(
home: new HomePage(),
debugShowCheckedModeBanner: false,
));
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'userDetails.dart';
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
@override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<UserDetails> _searchResult = [];
List<UserDetails> _userDetails = [];
TextEditingController controller = new TextEditingController();
// Get json result and convert it to model. Then add
Future<Null> getUserDetails() async {
final response = await http.get(url);
final responseJson = json.decode(response.body);
setState(() {
for (Map user in responseJson) {
_userDetails.add(UserDetails.fromJson(user));
}
});
}
@override
void initState() {
super.initState();
getUserDetails();
}
Widget _buildUsersList() {
return new ListView.builder(
itemCount: _userDetails.length,
itemBuilder: (context, index) {
return new Card(
child: new ListTile(
leading: new CircleAvatar(
backgroundImage: new NetworkImage(
_userDetails[index].profileUrl,
),
),
title: new Text(_userDetails[index].firstName +
' ' +
_userDetails[index].lastName),
),
margin: const EdgeInsets.all(0.0),
);
},
);
}
Widget _buildSearchResults() {
return new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, i) {
return new Card(
child: new ListTile(
leading: new CircleAvatar(
backgroundImage: new NetworkImage(
_searchResult[i].profileUrl,
),
),
title: new Text(
_searchResult[i].firstName + ' ' +_searchResult[i].lastName),
),
margin: const EdgeInsets.all(0.0),
);
},
);
}
Widget _buildSearchBox() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: onSearchTextChanged,
),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
controller.clear();
onSearchTextChanged('');
},
),
),
),
);
}
Widget _buildBody() {
return new Column(
children: <Widget>[
new Container(
color: Theme.of(context).primaryColor, child: _buildSearchBox()),
new Expanded(
child: _searchResult.length != 0 || controller.text.isNotEmpty
? _buildSearchResults()
: _buildUsersList()),
],
);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Home'),
elevation: 0.0,
),
body: _buildBody(),
resizeToAvoidBottomPadding: true,
);
}
onSearchTextChanged(String text) async {
_searchResult.clear();
if (text.isEmpty) {
setState(() {});
return;
}
_userDetails.forEach((userDetail) {
if (userDetail.firstName.contains(text) ||
userDetail.lastName.contains(text)) _searchResult.add(userDetail);
});
setState(() {});
}
}
import 'package:flutter/material.dart';
final String url = 'https://jsonplaceholder.typicode.com/users';
class UserDetails {
final int id;
final String firstName, lastName, profileUrl;
UserDetails({this.id, this.firstName, this.lastName, this.profileUrl = 'https://i.amz.mshcdn.com/3NbrfEiECotKyhcUhgPJHbrL7zM=/950x534/filters:quality(90)/2014%2F06%2F02%2Fc0%2Fzuckheadsho.a33d0.jpg'});
factory UserDetails.fromJson(Map<String, dynamic> json) {
return new UserDetails(
id: json['id'],
firstName: json['name'],
lastName: json['username'],
);
}
}
答案 6 :(得分:0)
这是另一种过滤列表的方法
_searchResult = _userDetails.where(
(userDetail) => (userDetail.firstName.contains(text) || userDetail.lastName.contains(text))
);
答案 7 :(得分:0)
将此添加到您的pub.yaml文件中:flutter_slidable:^ 0.5.4
import 'package:flutter/material.dart';
import 'produit_bloc.dart';
import 'produit_service.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class CRUDListView extends StatefulWidget {
@override
_CRUDListViewState createState() => _CRUDListViewState();
}
class _CRUDListViewState extends State<CRUDListView> {
List<Produit> _produits;
List<Produit> _searchProduct;
TextEditingController controller = new TextEditingController();
@override
void initState() {
super.initState();
_produits = [];
_searchProduct = [];
_getEmployees();
}
_getEmployees() {
ProduitService.getProduits().then((produits) {
setState(() {
_produits = produits;
});
print("Length ${produits.length} ");
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
appBar: new AppBar(
title: new Text('SEARCH ON LISTVIEW'),
elevation: 0.0,
),
body: new Column(
children: <Widget>[
new Container(
color: Theme.of(context).primaryColor,
child: new Padding(
padding: const EdgeInsets.all(8.0),
child: new Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: onSearchTextChanged,
),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
controller.clear();
onSearchTextChanged('');
},
),
),
),
),
),
new Expanded(
child: _searchProduct.length != 0 || controller.text.isNotEmpty
? new ListView.builder(
itemCount: _searchProduct.length,
itemBuilder: (context, i) {
return new Slidable(
actionPane: SlidableDrawerActionPane(),
actionExtentRatio: 0.25,
child: Container(
color: Colors.white,
child: ListTile(
leading: Text(('${_searchProduct[i].id}')),
title: Text(('${_searchProduct[i].article}')),
trailing: Text(('${_searchProduct[i].prixu}')),
),
),
actions: <Widget>[
IconSlideAction(
caption: 'Archive',
color: Colors.blue,
icon: Icons.archive,
onTap: () {
print('archive');
},
),
IconSlideAction(
caption: 'Share',
color: Colors.indigo,
icon: Icons.share,
onTap: () {
print('share');
},
),
],
secondaryActions: <Widget>[
IconSlideAction(
caption: 'More',
color: Colors.black45,
icon: Icons.more_horiz,
onTap: () {
print('more');
},
),
IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
onTap: () {
print('delete');
},
),
],
);
},
)
: new ListView.builder(
itemCount: _produits.length,
itemBuilder: (context, index) {
return new Slidable(
actionPane: SlidableDrawerActionPane(),
actionExtentRatio: 0.25,
child: Container(
color: Colors.white,
child: ListTile(
leading: Text(('${_produits[index].id}')),
title: Text(('${_produits[index].article}')),
trailing: Text(('${_produits[index].prixu}')),
),
),
actions: <Widget>[
IconSlideAction(
caption: 'Archive',
color: Colors.blue,
icon: Icons.archive,
onTap: () {
print('archive');
},
),
IconSlideAction(
caption: 'Share',
color: Colors.indigo,
icon: Icons.share,
onTap: () {
print('share');
},
),
],
secondaryActions: <Widget>[
IconSlideAction(
caption: 'More',
color: Colors.black45,
icon: Icons.more_horiz,
onTap: () {
print('more');
},
),
IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
onTap: () {
print('delete');
},
),
],
);
},
),
),
],
),
);
}
onSearchTextChanged(String text) async {
_searchProduct.clear();
if (text.isEmpty) {
setState(() {});
return;
}
_produits.forEach((produit) {
if (produit.article.contains(text) || produit.prixu.contains(text))
_searchProduct.add(produit);
});
setState(() {});
}
}
答案 8 :(得分:0)
有时setState((){})
可能不需要重建整个屏幕
在这种情况下,您可以使用ValuelistenableBuilder
小部件包装可搜索对象。
对此进行检查;
Widget searchableUsersWidget() {
List<Map> users = [
{'name': 'James', 'tel': '9010'},
{'name': 'Michael', 'tel': '9011'},
{'name': 'Jane', 'tel': '9013'},
];
ValueNotifier<List<Map>> filtered = ValueNotifier<List<Map>>([]);
TextEditingController searchController = TextEditingController();
FocusNode searchFocus = FocusNode();
bool searching = false;
return ValueListenableBuilder<List>(
valueListenable: filtered,
builder: (context, value, _) {
return Container(
margin: EdgeInsets.only(top: 10),
decoration: BoxDecoration(
color: shared.primaryBackgroundColor(),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20)),
boxShadow: [
BoxShadow(
color: Colors.white.withOpacity(0.5),
spreadRadius: 4,
blurRadius: 6,
offset: Offset(0, 3), // changes position of shadow
),
],
),
child: Column(
children: [
Container(
margin: EdgeInsets.all(8),
child: Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: searchController,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: (text) {
if (text.length > 0) {
searching = true;
filtered.value = [];
users.forEach((user) {
if (user['name']
.toString()
.toLowerCase()
.contains(text.toLowerCase()) ||
user['tel'].toString().contains(text)) {
filtered.value.add(user);
}
});
} else {
searching = false;
filtered.value = [];
}
},
),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
searchController.clear();
searching = false;
filtered.value = [];
if (searchFocus.hasFocus) searchFocus.unfocus();
},
),
),
),
),
Expanded(
child: ListView.builder(
itemCount: searching
? filtered.value.length
: users.length,
itemBuilder: (context, index) {
final item = searching
? filtered.value[index]
: users[index];
return ListTile(
leading: Avatar(
imageUrl: '',
color: Colors.amber,
),
title: Text(item['name']),
subtitle: Text(item['tel']),
onTap: () {},
);
}),
),
],
),
);
});
}
答案 9 :(得分:0)
您可以使用内置类SearchDelegate
答案 10 :(得分:0)
这是一个带有自动完成建议的搜索视图。以及最简单的 API 搜索方式
整合源码
1:直接将 pk_search_bar 目录拖放到您的 Flutter 项目中。
2 : 创建一个类 SearchScreen 并在 build
> Scaffold
> child: SearchBar()
创建模型类
class CountryModel {
String countryName;
String countryCode;
@override
String toString() {
return '$countryName $countryCode';
}
CountryModel(this.countryName, this.countryCode);
}
创建搜索屏幕
在这个类中,我们将调用过滤器并获取数据。然后我们将解析数据以获取用户的 CountryModel。
List<CountryModel> countryModelList = <CountryModel>[
CountryModel('Australia', 'AU'),
CountryModel('Egypt', 'EG'),
CountryModel('Germany', 'DE'),
CountryModel('India', 'IN'),
CountryModel('Singapore', 'SG'),
CountryModel('United States of America', 'US')
];
Future<List<CountryModel>> getCountrySearch(String search) async {
print("Resident search = $search");
if (search == "empty") return [];
if (search == "error") throw Error();
List<CountryModel> filterCountryList = [];
widget.countryModelList.forEach((CountryModel) {
if (CountryModel.countryName
.toLowerCase()
.contains(search.toLowerCase()) ||
CountryModel.countryCode
.toLowerCase()
.contains(search.toLowerCase()))
filterCountryList.add(CountryModel);
});
return filterCountryList;
}
// TODO: CountrySearchBar
Widget searchBar(BuildContext context) {
return SearchBar<CountryModel>(
searchBarPadding: EdgeInsets.only(left: 5, right: 5, top: 10, bottom: 5),
headerPadding: EdgeInsets.only(left: 0, right: 0),
listPadding: EdgeInsets.only(left: 0, right: 0),
hintText: "Search Placeholder",
hintStyle: TextStyle(
color: Colors.black54,
),
textStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.normal,
),
iconActiveColor: Colors.deepPurple,
shrinkWrap: true,
mainAxisSpacing: 5,
crossAxisSpacing: 5,
suggestions: widget.countryModelList,
cancellationWidget: Text("Cancel"),
minimumChars: 1,
// placeHolder: Center(
// child: Padding(
// padding: const EdgeInsets.only(left: 10, right: 10),
// child: Text(searchMessage, textAlign: TextAlign.center, style: CustomTextStyle.textSubtitle1(context).copyWith(fontSize: 14),),
// ),
// ),
emptyWidget: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Text("There is no any data found"),
),
),
onError: (error) {
return Center(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Text("$error", textAlign: TextAlign.center),
),
);
},
loader: Center(
child: LoadingIndicator(),
),
onSearch: getCountrySearchWithSuggestion, /// CountrySearch // if want to search with API then use thi ----> getCountryListFromApi
onCancelled: () {
Navigator.pop(context);
},
buildSuggestion: (CountryModel countryModel, int index) {
return countryGenerateColumn(countryModel, index);
},
onItemFound: (CountryModel countryModel, int index) {
return countryGenerateColumn(countryModel, index);
},
);
}
完整的源代码
import 'package:flutter/material.dart';
import 'package:fluttersearchviewpk/Constants.dart';
import 'package:page_transition/page_transition.dart';
import 'package:fluttersearchviewpk/pk_search_bar/pk_search_bar.dart';
import 'package:fluttersearchviewpk/DataListScreen.dart';
import 'package:flutter/services.dart';
class SearchScreen extends StatefulWidget {
final List<CountryModel> countryModelList;
@override
_SearchScreenState createState() => _SearchScreenState();
const SearchScreen(this.countryModelList);
}
class _SearchScreenState extends State<SearchScreen> {
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
return Scaffold(
body: SafeArea(
bottom: false,
child: Container(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: searchBar(context)),
)),
);
}
// TODO: CountrySearchBar
Widget searchBar(BuildContext context) {
return SearchBar<CountryModel>(
searchBarPadding: EdgeInsets.only(left: 5, right: 5, top: 10, bottom: 5),
headerPadding: EdgeInsets.only(left: 0, right: 0),
listPadding: EdgeInsets.only(left: 0, right: 0),
hintText: "Search Placeholder",
hintStyle: TextStyle(
color: Colors.black54,
),
textStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.normal,
),
iconActiveColor: Colors.deepPurple,
shrinkWrap: true,
mainAxisSpacing: 5,
crossAxisSpacing: 5,
suggestions: widget.countryModelList,
cancellationWidget: Text("Cancel"),
minimumChars: 1,
// placeHolder: Center(
// child: Padding(
// padding: const EdgeInsets.only(left: 10, right: 10),
// child: Text(searchMessage, textAlign: TextAlign.center, style: CustomTextStyle.textSubtitle1(context).copyWith(fontSize: 14),),
// ),
// ),
emptyWidget: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Text("There is no any data found"),
),
),
onError: (error) {
return Center(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Text("$error", textAlign: TextAlign.center),
),
);
},
loader: Center(
child: LoadingIndicator(),
),
onSearch: getCountrySearchWithSuggestion, /// CountrySearch // if want to search with API then use thi ----> getCountryListFromApi
onCancelled: () {
Navigator.pop(context);
},
buildSuggestion: (CountryModel countryModel, int index) {
return countryGenerateColumn(countryModel, index);
},
onItemFound: (CountryModel countryModel, int index) {
return countryGenerateColumn(countryModel, index);
},
);
}
Widget countryGenerateColumn(CountryModel countryModel, int index) => InkWell(
child: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
left: 5.0, top: 5.0, right: 5.0, bottom: 5.0),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: 50,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(8.0, 5.0, 0.0, 5.0),
width: MediaQuery.of(context).size.width * .60,
color: Colors.transparent,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(countryModel.countryName,
maxLines: 1,
overflow: TextOverflow.ellipsis
),
Text(
countryModel.countryCode,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 8),
Divider(height: 0.5)
],
),
),
],
),
),
),
],
),
);
Future<List<CountryModel>> getCountrySearch(String search) async {
print("Resident search = $search");
if (search == "empty") return [];
if (search == "error") throw Error();
List<CountryModel> filterCountryList = [];
widget.countryModelList.forEach((CountryModel) {
if (CountryModel.countryName
.toLowerCase()
.contains(search.toLowerCase()) ||
CountryModel.countryCode
.toLowerCase()
.contains(search.toLowerCase()))
filterCountryList.add(CountryModel);
});
return filterCountryList;
}
Future<List<CountryModel>> getCountrySearchWithSuggestion(
String search) async {
print("Resident search = $search");
if (search == "empty") return [];
if (search == "error") throw Error();
List<CountryModel> filterCountryList = [];
widget.countryModelList.forEach((CountryModel) {
if (CountryModel.countryName
.toLowerCase()
.contains(search.toLowerCase()) ||
CountryModel.countryCode
.toLowerCase()
.contains(search.toLowerCase()))
filterCountryList.add(CountryModel);
});
final suggestionList =
search.isEmpty ? widget.countryModelList : filterCountryList;
return suggestionList;
}
}
class LoadingIndicator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Center(
child: const CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.deepPurple),
),
);
}
}