Tile
Select Menu Tile
A tile that, when triggered, displays a list of options for the user to pick from.
For desktop, a select group is generally recommended over this.
enum Notification { all, direct, nothing }
FSelectMenuTile<Notification>.fromMap(
const {
'All': Notification.all,
'Direct Messages': Notification.direct,
'None': Notification.nothing,
},
selectControl: const FMultiValueControl.managed(initial: {Notification.all}),
autoHide: true,
validator: (value) => value == null ? 'Select an item' : null,
prefix: const Icon(FIcons.bell),
title: const Text('Notifications'),
detailsBuilder: (_, values, _) => Text(switch (values.firstOrNull) {
Notification.all => 'All',
Notification.direct => 'Direct Messages',
_ => 'None',
}),
);CLI
To generate and customize this style:
dart run forui style create select-menu-tileUsage
FSelectMenuTile(...)
FSelectMenuTile<Value>(
title: const Text('Notifications'),
menu: [
FSelectTile(title: const Text('Option 1'), value: Value.option1),
],
selectControl: FMultiValueControl.managed(initial: {Value.option1}),
popoverControl: FPopoverControl.managed(),
scrollController: ScrollController(),
style: (style) => style.copyWith(...),
cacheExtent: 100,
maxHeight: 200,
dragStartBehavior: DragStartBehavior.start,
physics: const ClampingScrollPhysics(),
divider: FItemDivider.indented,
menuAnchor: Alignment.topRight,
tileAnchor: Alignment.bottomRight,
menuSpacing: FPortalSpacing.spacing(4),
menuOverflow: FPortalOverflow.flip,
menuOffset: Offset.zero,
menuHideRegion: FPopoverHideRegion.excludeChild,
menuOnTapHide: () {},
menuGroupId: 'group-id',
autoHide: true,
label: const Text('Sidebar'),
description: const Text('Select the items you want to display in the sidebar.'),
autofocus: false,
menuFocusNode: FocusScopeNode(),
menuOnFocusChange: (focused) {},
menuTraversalEdgeBehavior: TraversalEdgeBehavior.closedLoop,
menuBarrierSemanticsLabel: 'Dismiss',
menuBarrierSemanticsDismissible: true,
semanticsLabel: 'Notifications',
prefix: const Icon(FIcons.bell),
subtitle: const Text('subtitle'),
detailsBuilder: (context, values, child) => const Placeholder(),
details: const Text('All'),
suffix: const Icon(FIcons.chevronsUpDown),
shortcuts: {SingleActivator(LogicalKeyboardKey.enter): ActivateIntent()},
actions: {ActivateIntent: CallbackAction<ActivateIntent>(onInvoke: (_) {})},
errorBuilder: (context, error) => Text(error),
onSaved: (values) {},
onReset: () {},
validator: (values) => values?.isEmpty ?? true ? 'Select an item' : null,
forceErrorText: null,
enabled: true,
autovalidateMode: AutovalidateMode.disabled,
);FSelectMenuTile.builder(...)
FSelectMenuTile<int>.builder(
title: const Text('Applicable values'),
menuBuilder: (context, index) => FSelectTile(title: Text('Tile $index'), value: index),
count: 100,
selectControl: FMultiValueControl.managed(initial: {1}),
popoverControl: FPopoverControl.managed(),
scrollController: ScrollController(),
style: (style) => style.copyWith(...),
cacheExtent: 100,
maxHeight: 200,
dragStartBehavior: DragStartBehavior.start,
physics: const ClampingScrollPhysics(),
divider: FItemDivider.indented,
menuAnchor: Alignment.topRight,
tileAnchor: Alignment.bottomRight,
menuSpacing: FPortalSpacing.spacing(4),
menuOverflow: FPortalOverflow.flip,
menuOffset: Offset.zero,
menuHideRegion: FPopoverHideRegion.excludeChild,
menuOnTapHide: () {},
menuGroupId: 'group-id',
autoHide: true,
label: const Text('Settings'),
description: const Text('Select the items you want to display.'),
autofocus: false,
menuFocusNode: FocusScopeNode(),
menuOnFocusChange: (focused) {},
menuTraversalEdgeBehavior: TraversalEdgeBehavior.closedLoop,
menuBarrierSemanticsLabel: 'Dismiss',
menuBarrierSemanticsDismissible: true,
semanticsLabel: 'Values',
prefix: const Icon(FIcons.variable),
subtitle: const Text('subtitle'),
detailsBuilder: (context, values, child) => const Placeholder(),
details: const Text('Details'),
suffix: const Icon(FIcons.chevronsUpDown),
shortcuts: {SingleActivator(LogicalKeyboardKey.enter): ActivateIntent()},
actions: {ActivateIntent: CallbackAction<ActivateIntent>(onInvoke: (_) {})},
errorBuilder: (context, error) => Text(error),
onSaved: (values) {},
onReset: () {},
validator: (values) => values?.isEmpty ?? true ? 'Select an item' : null,
forceErrorText: null,
enabled: true,
autovalidateMode: AutovalidateMode.disabled,
);Examples
No Auto Hide
enum Notification { all, direct, nothing }
FSelectMenuTile<Notification>(
selectControl: const FMultiValueControl.managed(initial: {Notification.all}),
autoHide: false,
validator: (value) => value == null ? 'Select an item' : null,
prefix: const Icon(FIcons.bell),
title: const Text('Notifications'),
detailsBuilder: (_, values, _) => Text(switch (values.firstOrNull) {
Notification.all => 'All',
Notification.direct => 'Direct Messages',
_ => 'None',
}),
menu: const [
FSelectTile(title: Text('All'), value: Notification.all),
FSelectTile(title: Text('Direct Messages'), value: Notification.direct),
FSelectTile(title: Text('None'), value: Notification.nothing),
],
);Scrollable
enum Notification { all, direct, limitedTime, timeSensitive, selectedApps, nothing }
FSelectMenuTile<Notification>(
selectControl: const FMultiValueControl.managed(initial: {Notification.all}),
maxHeight: 150,
validator: (value) => value == null ? 'Select an item' : null,
prefix: const Icon(FIcons.bell),
title: const Text('Notifications'),
detailsBuilder: (_, values, _) => Text(switch (values.firstOrNull) {
Notification.all => 'All',
Notification.direct => 'Direct Messages',
Notification.limitedTime => 'Limited Time',
Notification.selectedApps => 'Selected Apps',
Notification.timeSensitive => 'Time Sensitive',
null || Notification.nothing => 'None',
}),
menu: const [
FSelectTile(title: Text('All'), value: Notification.all),
FSelectTile(title: Text('Direct Messages'), value: Notification.direct),
FSelectTile(title: Text('Limited Time'), value: Notification.limitedTime),
FSelectTile(title: Text('Selected Apps'), value: Notification.selectedApps),
FSelectTile(title: Text('Time Sensitive'), value: Notification.timeSensitive),
FSelectTile(title: Text('None'), value: Notification.nothing),
],
);Lazy Scrollable
FSelectMenuTile<int>.builder(
selectControl: const FMultiValueControl.managed(initial: {1}),
prefix: const Icon(FIcons.variable),
title: const Text('Applicable values'),
maxHeight: 200,
menuBuilder: (context, index) => FSelectTile(title: Text('Tile $index'), value: index),
);Form
enum Notification { all, direct, nothing }
class SelectMenuTileForm extends StatefulWidget {
const SelectMenuTileForm({super.key});
@override
State<SelectMenuTileForm> createState() => _SelectMenuTileFormState();
}
class _SelectMenuTileFormState extends State<SelectMenuTileForm> {
final _key = GlobalKey<FormState>();
@override
Widget build(BuildContext context) => Form(
key: _key,
child: Column(
mainAxisSize: MainAxisSize.min,
spacing: 20,
children: [
FSelectMenuTile<Notification>(
selectControl: const FMultiValueControl.managed(initial: {Notification.all}),
validator: (value) => value == null ? 'Select an item' : null,
prefix: const Icon(FIcons.bell),
title: const Text('Notifications'),
detailsBuilder: (_, values, _) => Text(switch (values.firstOrNull) {
Notification.all => 'All',
Notification.direct => 'Direct Messages',
_ => 'None',
}),
menu: const [
FSelectTile(title: Text('All'), value: Notification.all),
FSelectTile(title: Text('Direct Messages'), value: Notification.direct),
FSelectTile(title: Text('None'), value: Notification.nothing),
],
),
FButton(
child: const Text('Save'),
onPress: () {
if (!_key.currentState!.validate()) {
// Handle errors here.
return;
}
_key.currentState!.save();
// Do something.
},
),
],
),
);
}