show<T> static method

Future<MySelectorResult<T>> show<T>({
  1. required BuildContext triggerContext,
  2. required List<MySelectorItem<T>> items,
  3. T? currentValue,
  4. MySelectorClearOption? clearOption,
  5. bool allowReselect = false,
  6. MyPanelPlacement placement = MyPanelPlacement.below,
  7. bool showSearch = false,
  8. String searchHint = '搜索…',
  9. bool searchFilter(
    1. MySelectorItem<T> item,
    2. String query
    )?,
  10. Widget itemBuilder(
    1. BuildContext context,
    2. MySelectorItem<T> item,
    3. bool isSelected
    )?,
  11. Widget footerBuilder(
    1. BuildContext,
    2. VoidCallback
    )?,
  12. MySelectorStyle? style,
})

弹出选择器面板,返回 MySelectorResult 告知调用方用户的操作意图。

Implementation

static Future<MySelectorResult<T>> show<T>({
  required BuildContext triggerContext,
  required List<MySelectorItem<T>> items,
  T? currentValue,
  // 清除 & 复选取消
  MySelectorClearOption? clearOption,
  bool allowReselect = false,
  // 弹出方向策略(默认首选向下、放不下才上翻),详见 [MyPanelPlacement]。
  MyPanelPlacement placement = MyPanelPlacement.below,
  // 搜索
  bool showSearch = false,
  String searchHint = '搜索…',
  bool Function(MySelectorItem<T> item, String query)? searchFilter,
  // 自定义渲染
  Widget Function(
    BuildContext context,
    MySelectorItem<T> item,
    bool isSelected,
  )? itemBuilder,
  Widget Function(BuildContext context, VoidCallback dismiss)? footerBuilder,
  // 样式
  MySelectorStyle? style,
}) async {
  assert(items.isNotEmpty, 'items 不能为空');

  final effectiveStyle = style ?? MySelectorStyle();
  final completer = Completer<MySelectorResult<T>>();

  final renderBox = triggerContext.findRenderObject() as RenderBox;
  final overlayState = Overlay.of(triggerContext, rootOverlay: true);

  // 捕获触发处的环境文字样式与文字缩放,供面板测宽时精确对齐实际渲染
  // (避免用默认字体/缩放测量导致偏差 → 内容被省略号截断)。
  final ambientTextStyle = DefaultTextStyle.of(triggerContext).style;
  final textScaler = MediaQuery.textScalerOf(triggerContext);
  final measuredContentWidth =
      effectiveStyle.panelWidth == null && itemBuilder != null
          ? await _measureItemBuilderContentWidth<T>(
              triggerContext: triggerContext,
              overlayState: overlayState,
              items: items,
              currentValue: currentValue,
              itemBuilder: itemBuilder,
              footerBuilder: footerBuilder,
            )
          : null;

  late OverlayEntry entry;

  void dismiss(MySelectorResult<T> result) {
    entry.remove();
    if (!completer.isCompleted) {
      completer.complete(result);
    }
  }

  entry = OverlayEntry(
    builder: (_) => _SelectorOverlay<T>(
      renderBox: renderBox,
      overlayState: overlayState,
      items: items,
      currentValue: currentValue,
      clearOption: clearOption,
      allowReselect: allowReselect,
      placement: placement,
      measuredContentWidth: measuredContentWidth,
      ambientTextStyle: ambientTextStyle,
      textScaler: textScaler,
      showSearch: showSearch,
      searchHint: searchHint,
      searchFilter: searchFilter,
      itemBuilder: itemBuilder,
      footerBuilder: footerBuilder,
      style: effectiveStyle,
      onSelected: (item) =>
          dismiss(MySelectorValueChanged(item.value, item: item)),
      onCleared: () => dismiss(MySelectorValueChanged(null)),
      onDismiss: () => dismiss(MySelectorDismissed()),
    ),
  );

  overlayState.insert(entry);
  return completer.future;
}