openHourMinutePickerPopupLive function

Future<void> openHourMinutePickerPopupLive({
  1. required BuildContext context,
  2. required HourMinute initialValue,
  3. HourMinute? minValue,
  4. HourMinute? maxValue,
  5. required void onChanged(
    1. HourMinute newValue
    ),
})

HourMinute ピッカーをポップアップメニューとして表示する

context - 表示するコンテキスト(通常はボタンのcontext) initialValue - 初期値 minValue - 最小値(オプション) maxValue - 最大値(オプション) onChanged - 値が変更されたときのコールバック(ホイールのスクロールが止まったときに呼ばれる)

戻り値: ポップアップが閉じられるまで待機するFuture

Implementation

Future<void> openHourMinutePickerPopupLive({
  required BuildContext context,
  required HourMinute initialValue,
  HourMinute? minValue,
  HourMinute? maxValue,
  required void Function(HourMinute newValue) onChanged,
}) {
  final RenderBox button = context.findRenderObject() as RenderBox;
  final RenderBox overlay =
      Overlay.of(context).context.findRenderObject() as RenderBox;
  final Offset position = button.localToGlobal(Offset.zero, ancestor: overlay);
  final Size screenSize = MediaQuery.of(context).size;

  const double margin = 16.0;
  const double menuWidth = 300.0;

  // 画面端からの余白を考慮した位置調整
  double left = position.dx;
  double right = screenSize.width - position.dx - button.size.width;

  // 右端に近すぎる場合は左に寄せる
  if (left + menuWidth > screenSize.width - margin) {
    left = screenSize.width - menuWidth - margin;
    right = margin;
  }

  // 左端に近すぎる場合は右に寄せる
  if (left < margin) {
    left = margin;
    right = screenSize.width - menuWidth - margin;
  }

  return showMenu<void>(
    context: context,
    color: Colors.white,
    surfaceTintColor: Colors.transparent,
    elevation: 8,
    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
    position: RelativeRect.fromLTRB(
      left,
      position.dy + button.size.height + 8,
      right,
      screenSize.height - position.dy - button.size.height - margin,
    ),
    items: [
      PopupMenuItem<void>(
        enabled: false,
        padding: EdgeInsets.zero,
        child: SizedBox(
          width: menuWidth,
          child: _HourMinutePickerPopupLiveContent(
            initialValue: initialValue,
            minValue: minValue,
            maxValue: maxValue,
            onChanged: onChanged,
            onComplete: () {
              Navigator.pop(context);
            },
          ),
        ),
      ),
    ],
  );
}