You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中showTimePicker点击任意选项均返回null问题求助

解决iOS上Flutter showTimePicker弹窗点击即关闭返回null的问题

看起来你遇到的是iOS环境下showTimePicker的交互异常问题——弹窗能正常弹出,但点击任何内容都会直接关闭并返回null。结合你提到的父组件有自定义Navigator的情况,我有几个针对性的解决方案:

1. 使用根Navigator的上下文调用showTimePicker

当你的页面嵌套在自定义Navigator中时,当前State的context可能属于这个子Navigator层级,导致showTimePicker的弹窗挂载上下文不正确,进而引发交互异常。你可以通过Navigator.of(context, rootNavigator: true)获取根Navigator的上下文来调用弹窗:

修改你的_pickNewDailyResetTime方法:

_pickNewDailyResetTime() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  // 使用根Navigator的context
  final selectedTime = await showTimePicker(
    context: Navigator.of(context, rootNavigator: true),
    initialTime: _dailyResetTime,
  );
  
  if (selectedTime == null) {
    return;
  }
  setState(() {
    _dailyResetTime = selectedTime;
    prefs.setString('dailyResetTime', '${selectedTime.hour}:${selectedTime.minute}');
  });
}

这个修改应该能解决大部分因上下文层级不匹配导致的弹窗交互问题。

2. 尝试替换InkWell为GestureDetector

虽然你通过断点确认了_pickNewDailyResetTime没有被误触发,但iOS上的手势识别优先级有时会有特殊情况。你可以尝试将InkWell替换为GestureDetector,看看是否能规避潜在的手势冲突:

@override
Widget build(BuildContext context) {
  return GestureDetector(
    onTap: _pickNewDailyResetTime,
    child: Container(
        height: 48.0,
        padding: EdgeInsets.only(right: 24),
        decoration: BoxDecoration(
            border: Border(
                bottom: BorderSide(color: Colors.black12, width: 1.0))),
        child: Row(
          children: [
            Text('Daily reset time'),
            Spacer(),
            Text(_dailyResetTime?.format(context) ?? '')
          ],
        )));
}

3. 优化SharedPreferences的异步操作(可选)

虽然这不是导致弹窗问题的直接原因,但将嵌套的then改为async/await可以让代码更清晰易读,也能避免潜在的异步逻辑问题:

_pickNewDailyResetTime() async {
  final prefs = await SharedPreferences.getInstance();
  final selectedTime = await showTimePicker(
    context: Navigator.of(context, rootNavigator: true),
    initialTime: _dailyResetTime,
  );

  if (selectedTime == null) return;

  setState(() {
    _dailyResetTime = selectedTime;
  });
  // 单独执行存储操作,避免在setState中做异步操作
  await prefs.setString(
    'dailyResetTime',
    '${selectedTime.hour}:${selectedTime.minute}',
  );
}

验证思路

你提到父组件配置了单个Navigator,这是关键线索——Flutter的弹窗类组件(比如showTimePicker、showDialog)依赖正确的导航上下文来管理弹窗的生命周期和交互。如果使用了子Navigator的上下文,弹窗的手势事件可能会被父级Navigator拦截,导致点击后直接关闭。

先尝试第一个方案(使用根Navigator上下文),这应该是最直接解决问题的办法。

内容的提问来源于stack exchange,提问作者Yoan Desforges

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 17:37:57