FSelectMenuTile<T> constructor
FSelectMenuTile<T> ({
- required FSelectGroupController<
T> groupController, - required Widget title,
- FPopoverController? popoverController,
- FSelectMenuTileStyle? style,
- FTileDivider divider = FTileDivider.full,
- Alignment tileAnchor = Alignment.bottomRight,
- Offset shift() = FPortalFollowerShift.flip,
- bool hideOnTapOutside = true,
- bool ignoreDirectionalPadding = true,
- bool autoHide = false,
- Widget? label,
- Widget? description,
- Widget errorBuilder() = _errorBuilder,
- String? semanticLabel,
- bool autofocus = false,
- FocusNode? focusNode,
- ValueChanged<
bool> ? onFocusChange, - Widget? prefixIcon,
- Widget? subtitle,
- Widget? details,
- Widget? suffixIcon,
- FormFieldSetter<
Set< ? onSaved,T> > - FormFieldValidator<
Set< ? validator,T> > - Set<
T> ? initialValue, - String? forceErrorText,
- bool enabled = true,
- AutovalidateMode? autovalidateMode,
- String? restorationId,
- Key? key,
Creates a FSelectMenuTile.
Implementation
FSelectMenuTile({
required this.groupController,
required this.menu,
required this.title,
this.popoverController,
this.style,
this.divider = FTileDivider.full,
this.menuAnchor = Alignment.topRight,
this.tileAnchor = Alignment.bottomRight,
this.shift = FPortalFollowerShift.flip,
this.hideOnTapOutside = true,
this.ignoreDirectionalPadding = true,
this.autoHide = false,
this.label,
this.description,
this.errorBuilder = _errorBuilder,
this.semanticLabel,
this.autofocus = false,
this.focusNode,
this.onFocusChange,
this.prefixIcon,
this.subtitle,
this.details,
this.suffixIcon,
super.onSaved,
super.validator,
super.initialValue,
super.forceErrorText,
super.enabled = true,
super.autovalidateMode,
super.restorationId,
super.key,
}) : super(
builder: (field) {
final state = field as _State<T>;
final groupData = FTileGroupData.maybeOf(state.context);
final tileData = FTileData.maybeOf(state.context);
final global = state.context.theme.selectMenuTileStyle;
final labelStyle = style?.labelStyle ?? global.labelStyle;
final menuStyle = style?.menuStyle ?? global.menuStyle;
final tileStyle = style?.tileStyle ?? tileData?.style ?? groupData?.style.tileStyle ?? global.tileStyle;
final (labelState, error) = switch (state.errorText) {
_ when !enabled => (FLabelState.disabled, null),
final text? => (FLabelState.error, errorBuilder(state.context, text)),
null => (FLabelState.enabled, null),
};
Widget tile = FPopover(
// A GlobalObjectKey is used to workaround Flutter not recognizing how widgets move inside the widget tree.
//
// OverlayPortalControllers are tied to a single _OverlayPortalState, and conditional rebuilds introduced
// by FLabel and its internals can cause a new parent to be inserted above FPopover. This leads to the
// entire widget subtree being rebuilt and losing their state. Consequently, the controller is assigned
// another _OverlayPortalState, causing an assertion to be thrown.
//
// See https://stackoverflow.com/a/59410824/4189771
key: GlobalObjectKey(state._controller._popover),
controller: state._controller._popover,
style: menuStyle,
followerAnchor: menuAnchor,
targetAnchor: tileAnchor,
shift: shift,
hideOnTapOutside: hideOnTapOutside,
ignoreDirectionalPadding: ignoreDirectionalPadding,
autofocus: autofocus,
focusNode: focusNode,
onFocusChange: onFocusChange,
followerBuilder: (context, _, __) => ConstrainedBox(
constraints: BoxConstraints(maxWidth: menuStyle.maxWidth),
child: FSelectTileGroup<T>(
controller: state._controller,
style: menuStyle.tileGroupStyle,
semanticLabel: semanticLabel,
divider: divider,
children: menu,
),
),
target: FTile(
style: tileStyle,
prefixIcon: prefixIcon,
enabled: enabled,
title: title,
subtitle: subtitle,
details: details,
suffixIcon: suffixIcon ?? FIcon(FAssets.icons.chevronsUpDown),
onPress: state._controller._popover.toggle,
),
);
if (groupData == null && tileData == null && (label != null || description != null || error != null)) {
tile = FLabel(
axis: Axis.vertical,
style: labelStyle,
state: labelState,
label: label,
description: description,
error: error,
child: tile,
);
}
return tile;
},
);