Autocomplete
On this page
Code summary
The Autocomplete
component is used on the Ecommerce UI demo app search page when you tap the search bar in the main page. It consists of two sections: one presenting the search history and the second one presenting the query suggestions.
The AppBar
includes SearchHeaderView
` widget representing the search box on the autocomplete screen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class SearchHeaderView extends StatelessWidget {
const SearchHeaderView(
{Key? key, required this.controller, this.onSubmitted, this.onChanged})
: super(key: key);
final TextEditingController controller;
final ValueChanged<String>? onChanged;
final ValueChanged<String>? onSubmitted;
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: TextField(
autofocus: true,
controller: controller,
onSubmitted: onSubmitted,
onChanged: onChanged,
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "Search products, articles, faq, ..."),
),
),
if (controller.text.isNotEmpty)
IconButton(
iconSize: 34,
onPressed: controller.clear,
icon: const Icon(Icons.clear),
color: AppTheme.darkBlue),
const SizedBox(width: 8)
],
);
}
}
Each section consists of couple of SliverAppBar
and SliverList
components representing the section header and section body respectively.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Widget _sectionHeader<Item>(Stream<List<Item>> itemsStream, Widget title) =>
StreamBuilder<List<Item>>(
stream: itemsStream,
builder: (context, snapshot) {
final suggestions = snapshot.data ?? [];
return SliverSafeArea(
top: false,
bottom: false,
sliver: SliverPadding(
padding: const EdgeInsets.only(left: 15),
sliver: SliverToBoxAdapter(
child:
suggestions.isEmpty ? const SizedBox.shrink() : title,
)));
});
Widget _sectionBody<Item>(
BuildContext context,
Stream<List<Item>> itemsStream,
Function(Item) rowBuilder,
) =>
StreamBuilder<List<Item>>(
stream: itemsStream,
builder: (context, snapshot) {
final suggestions = snapshot.data ?? [];
if (suggestions.isEmpty) {
return const SliverToBoxAdapter(child: SizedBox.shrink());
}
return SliverSafeArea(
top: false,
sliver: SliverPadding(
padding: const EdgeInsets.only(left: 15),
sliver: SliverFixedExtentList(
itemExtent: 44,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
final item = suggestions[index];
return InkWell(
onTap: () {
final query = item.toString();
_onSubmitSearch(query, context);
},
child: rowBuilder(item));
},
childCount: suggestions.length,
))));
});
The first section represents the search history. All the submitted search queries are stored in the Autocomplete screen state. Users can delete each history item or remove them all by tapping the corresponding button in the section header.
Each history row is represented by a HistoryRowView
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class HistoryRowView extends StatelessWidget {
const HistoryRowView({Key? key, required this.suggestion, this.onRemove})
: super(key: key);
final String suggestion;
final Function(String)? onRemove;
@override
Widget build(BuildContext context) {
return Row(children: [
const Icon(Icons.refresh),
const SizedBox(
width: 10,
),
Text(suggestion, style: const TextStyle(fontSize: 16)),
const Spacer(),
IconButton(
onPressed: () => onRemove?.call(suggestion),
icon: const Icon(Icons.close)),
]);
}
}
The second section represents the query suggestions. By default it shows the list of popular searches. When user starts typing a search query the list is refreshing automatically and presents the highlighted search completions.
Each suggestion row is represented by a SuggestionRowView
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class SuggestionRowView extends StatelessWidget {
const SuggestionRowView({Key? key, required this.suggestion, this.onComplete})
: super(key: key);
final QuerySuggestion suggestion;
final Function(String)? onComplete;
@override
Widget build(BuildContext context) {
return Row(children: [
const Icon(Icons.search),
const SizedBox(
width: 10,
),
RichText(
text: TextSpan(
style: const TextStyle(color: Colors.black),
children: suggestion.highlighted!.toInlineSpans())),
const Spacer(),
IconButton(
onPressed: () => onComplete?.call(suggestion.query),
icon: const Icon(Icons.north_west),
)
]);
}
}
The highlighting of the suggestion row is possible through HighlightedString.toInlineSpans()
from Flutter helpers.
The entire autocomplete logic can be found in the autocomplete_screen
file.
You can customize Autocomplete
in: