mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Add a SearchAnchor example to experimental demo (#1722)
This commit is contained in:
@@ -140,8 +140,8 @@ class Navigation extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
NavigationDrawers(scaffoldKey: scaffoldKey),
|
NavigationDrawers(scaffoldKey: scaffoldKey),
|
||||||
const NavigationRails(),
|
const NavigationRails(),
|
||||||
// TODO: Add Search https://github.com/flutter/flutter/issues/117483
|
|
||||||
const Tabs(),
|
const Tabs(),
|
||||||
|
const SearchAnchors(),
|
||||||
const TopAppBars(),
|
const TopAppBars(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -2182,6 +2182,101 @@ class _SlidersState extends State<Sliders> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SearchAnchors extends StatefulWidget {
|
||||||
|
const SearchAnchors({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SearchAnchors> createState() => _SearchAnchorsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SearchAnchorsState extends State<SearchAnchors> {
|
||||||
|
String? selectedColor;
|
||||||
|
List<ColorItem> searchHistory = <ColorItem>[];
|
||||||
|
|
||||||
|
Iterable<Widget> getHistoryList(SearchController controller) {
|
||||||
|
return searchHistory.map((color) => ListTile(
|
||||||
|
leading: const Icon(Icons.history),
|
||||||
|
title: Text(color.label),
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: const Icon(Icons.call_missed),
|
||||||
|
onPressed: () {
|
||||||
|
controller.text = color.label;
|
||||||
|
controller.selection =
|
||||||
|
TextSelection.collapsed(offset: controller.text.length);
|
||||||
|
}),
|
||||||
|
onTap: () {
|
||||||
|
controller.closeView(color.label);
|
||||||
|
handleSelection(color);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterable<Widget> getSuggestions(SearchController controller) {
|
||||||
|
final String input = controller.value.text;
|
||||||
|
return ColorItem.values
|
||||||
|
.where((color) => color.label.contains(input))
|
||||||
|
.map((filteredColor) => ListTile(
|
||||||
|
leading: CircleAvatar(backgroundColor: filteredColor.color),
|
||||||
|
title: Text(filteredColor.label),
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: const Icon(Icons.call_missed),
|
||||||
|
onPressed: () {
|
||||||
|
controller.text = filteredColor.label;
|
||||||
|
controller.selection =
|
||||||
|
TextSelection.collapsed(offset: controller.text.length);
|
||||||
|
}),
|
||||||
|
onTap: () {
|
||||||
|
controller.closeView(filteredColor.label);
|
||||||
|
handleSelection(filteredColor);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleSelection(ColorItem color) {
|
||||||
|
setState(() {
|
||||||
|
selectedColor = color.label;
|
||||||
|
if (searchHistory.length >= 5) {
|
||||||
|
searchHistory.removeLast();
|
||||||
|
}
|
||||||
|
searchHistory.insert(0, color);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ComponentDecoration(
|
||||||
|
label: 'Search',
|
||||||
|
tooltipMessage: 'Use SearchAnchor or SearchAnchor.bar',
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
SearchAnchor.bar(
|
||||||
|
barHintText: 'Search colors',
|
||||||
|
suggestionsBuilder: (context, controller) {
|
||||||
|
if (controller.text.isEmpty) {
|
||||||
|
if (searchHistory.isNotEmpty) {
|
||||||
|
return getHistoryList(controller);
|
||||||
|
}
|
||||||
|
return <Widget>[
|
||||||
|
const Center(
|
||||||
|
child: Text('No search history.',
|
||||||
|
style: TextStyle(color: Colors.grey)),
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return getSuggestions(controller);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
if (selectedColor == null)
|
||||||
|
const Text('Select a color')
|
||||||
|
else
|
||||||
|
Text('Last selected color is $selectedColor')
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ComponentDecoration extends StatefulWidget {
|
class ComponentDecoration extends StatefulWidget {
|
||||||
const ComponentDecoration({
|
const ComponentDecoration({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -2291,3 +2386,26 @@ class ComponentGroupDecoration extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ColorItem {
|
||||||
|
red('red', Colors.red),
|
||||||
|
orange('orange', Colors.orange),
|
||||||
|
yellow('yellow', Colors.yellow),
|
||||||
|
green('green', Colors.green),
|
||||||
|
blue('blue', Colors.blue),
|
||||||
|
indigo('indigo', Colors.indigo),
|
||||||
|
violet('violet', Color(0xFF8F00FF)),
|
||||||
|
purple('purple', Colors.purple),
|
||||||
|
pink('pink', Colors.pink),
|
||||||
|
silver('silver', Color(0xFF808080)),
|
||||||
|
gold('gold', Color(0xFFFFD700)),
|
||||||
|
beige('beige', Color(0xFFF5F5DC)),
|
||||||
|
brown('brown', Colors.brown),
|
||||||
|
grey('grey', Colors.grey),
|
||||||
|
black('black', Colors.black),
|
||||||
|
white('white', Colors.white);
|
||||||
|
|
||||||
|
const ColorItem(this.label, this.color);
|
||||||
|
final String label;
|
||||||
|
final Color color;
|
||||||
|
}
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ void main() {
|
|||||||
// Tabs
|
// Tabs
|
||||||
expect(find.byType(TabBar), findsOneWidget);
|
expect(find.byType(TabBar), findsOneWidget);
|
||||||
|
|
||||||
|
// Search
|
||||||
|
expect(find.byType(SearchBar), findsOneWidget);
|
||||||
|
|
||||||
// Top app bars
|
// Top app bars
|
||||||
expect(find.byType(AppBar), findsNWidgets(6));
|
expect(find.byType(AppBar), findsNWidgets(6));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user