flutter - 带有自动完成功能的 Flutter 搜索栏
问题描述
我正在寻找颤振文档中的搜索栏但找不到它,是否有用于搜索栏的小部件,在 appbar 中具有自动完成功能。例如,我的应用栏上有一个搜索图标。一按它就会显示搜索框,当您键入它时,它应该会从带有 listtile 的下拉列表中显示自动完成。我设法实现了这一点,但它并不容易使用,因为我需要一个下拉列表来显示建议自动完成,然后在选择时使用新路线的建议。
解决方案
你可以使用 Stack 来实现自动完成的下拉框效果。下面的示例有 2 个容器 - 都ListView
作为子对象保存。一个包含搜索结果,另一个包含一些随机文本作为正文的内容。ListView
(搜索结果)放置在对齐对象内,对齐属性设置为 Alignment.topCenter。这样可以确保 List 出现在顶部,就在AppBar
.
更新了评论中提到的帖子(已接受的答案)以获得完整的演示。
如上所述:
@override
Widget build(BuildContext context) {
return new Scaffold(
key: key,
appBar: buildBar(context),
body: new Stack(
children: <Widget>[
new Container(
height: 300.0,
padding: EdgeInsets.all(10.0),
child: new DefaultTabController(length: 5, child: mainTabView),
),
displaySearchResults(),
],
));
}
Widget displaySearchResults() {
if (_IsSearching) {
return new Align(
alignment: Alignment.topCenter,
//heightFactor: 0.0,
child: searchList());
} else {
return new Align(alignment: Alignment.topCenter, child: new Container());
}
}
完整的演示
class SearchList extends StatefulWidget {
SearchList({Key key, this.name}) : super(key: key);
final String name;
@override
_SearchListState createState() => new _SearchListState();
}
class _SearchListState extends State<SearchList> {
Widget appBarTitle = new Text(
"",
style: new TextStyle(color: Colors.white),
);
Icon actionIcon = new Icon(
Icons.search,
color: Colors.white,
);
final key = new GlobalKey<ScaffoldState>();
final TextEditingController _searchQuery = new TextEditingController();
List<SearchResult> _list;
bool _IsSearching;
String _searchText = "";
String selectedSearchValue = "";
_SearchListState() {
_searchQuery.addListener(() {
if (_searchQuery.text.isEmpty) {
setState(() {
_IsSearching = false;
_searchText = "";
});
} else {
setState(() {
_IsSearching = true;
_searchText = _searchQuery.text;
});
}
});
}
@override
void initState() {
super.initState();
_IsSearching = false;
createSearchResultList();
}
void createSearchResultList() {
_list = <SearchResult>[
new SearchResult(name: 'Google'),
new SearchResult(name: 'IOS'),
new SearchResult(name: 'IOS2'),
new SearchResult(name: 'Android'),
new SearchResult(name: 'Dart'),
new SearchResult(name: 'Flutter'),
new SearchResult(name: 'Python'),
new SearchResult(name: 'React'),
new SearchResult(name: 'Xamarin'),
new SearchResult(name: 'Kotlin'),
new SearchResult(name: 'Java'),
new SearchResult(name: 'RxAndroid'),
];
}
@override
Widget build(BuildContext context) {
return new Scaffold(
key: key,
appBar: buildBar(context),
body: new Stack(
children: <Widget>[
new Container(
height: 300.0,
padding: EdgeInsets.all(10.0),
child: new Container(
child: ListView(
children: <Widget>[
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
new Text("Hello World!"),
],
),
),
),
displaySearchResults(),
],
));
}
Widget displaySearchResults() {
if (_IsSearching) {
return new Align(
alignment: Alignment.topCenter,
child: searchList());
} else {
return new Align(alignment: Alignment.topCenter, child: new Container());
}
}
ListView searchList() {
List<SearchResult> results = _buildSearchList();
return ListView.builder(
itemCount: _buildSearchList().isEmpty == null ? 0 : results.length,
itemBuilder: (context, int index) {
return Container(
decoration: new BoxDecoration(
color: Colors.grey[100],
border: new Border(
bottom: new BorderSide(
color: Colors.grey,
width: 0.5
)
)
),
child: ListTile(
onTap: (){},
title: Text(results.elementAt(index).name,
style: new TextStyle(fontSize: 18.0)),
),
);
},
);
}
List<SearchResult> _buildList() {
return _list.map((result) => new SearchResult(name: result.name)).toList();
}
List<SearchResult> _buildSearchList() {
if (_searchText.isEmpty) {
return _list.map((result) => new SearchResult(name: result.name)).toList();
} else {
List<SearchResult> _searchList = List();
for (int i = 0; i < _list.length; i++) {
SearchResult result = _list.elementAt(i);
if ((result.name).toLowerCase().contains(_searchText.toLowerCase())) {
_searchList.add(result);
}
}
return _searchList
.map((result) => new SearchResult(name: result.name))
.toList();
}
}
Widget buildBar(BuildContext context) {
return new AppBar(
centerTitle: true,
title: appBarTitle,
actions: <Widget>[
new IconButton(
icon: actionIcon,
onPressed: () {
_displayTextField();
},
),
// new IconButton(icon: new Icon(Icons.more), onPressed: _IsSearching ? _showDialog(context, _buildSearchList()) : _showDialog(context,_buildList()))
],
);
}
String selectedPopupRoute = "My Home";
final List<String> popupRoutes = <String>[
"My Home",
"Favorite Room 1",
"Favorite Room 2"
];
void _displayTextField() {
setState(() {
if (this.actionIcon.icon == Icons.search) {
this.actionIcon = new Icon(
Icons.close,
color: Colors.white,
);
this.appBarTitle = new TextField(
autofocus: true,
controller: _searchQuery,
style: new TextStyle(
color: Colors.white,
),
);
_handleSearchStart();
} else {
_handleSearchEnd();
}
});
}
void _handleSearchStart() {
setState(() {
_IsSearching = true;
});
}
void _handleSearchEnd() {
setState(() {
this.actionIcon = new Icon(
Icons.search,
color: Colors.white,
);
this.appBarTitle = new Text(
"",
style: new TextStyle(color: Colors.white),
);
_IsSearching = false;
_searchQuery.clear();
});
}
}
推荐阅读
- java - Jboss EAP AMQ119032:用户没有地址上的 CREATE_DURABLE_QUEUE 权限
- java - 解密 SAML 响应
- c - 为什么我不能 mmap /proc/self/maps?
- node.js - 未处理的拒绝(TypeError):从后端提取数据时调度不是函数错误
- python - Telegram 的 websocket
- python - 如何使用 groupby 函数从表中找到特定值?
- android - 如何为 Hilt Android 提供上下文?
- azure - Azure 组合警报指标
- gitlab - 尝试 lint 我的 gitlab-ci.yml(版本 13.8)时获取 à 401 Unauthorized
- json - 我收到颤振类型错误“响应”不是“FutureOr”的子类型
'