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

Flutter点击InkWell的onTap时出现Unexpected null value错误求助

Flutter InkWell点击触发Unexpected null value空值错误

点击编辑图标(InkWell组件)触发imagePickerOption函数时,抛出Unexpected null value空值错误,错误栈信息如下:

======== Exception caught by gesture ===============================================================
The following TypeErrorImpl was thrown while handling a gesture:
Unexpected null value.

When the exception was thrown, this was the stack: 
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:49           throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 855:63       nullCheck
packages/get/get_navigation/src/extension_navigation.dart 36:39                        ExtensionBottomSheet.bottomSheet
packages/agriplus/Registration%20Screens/Signup%2520Screens/signup_screen_5.dart 48:9  imagePickerOption
packages/flutter/src/material/ink_well.dart 1154:21                                    handleTap
packages/flutter/src/gestures/recognizer.dart 275:24                                   invokeCallback
packages/flutter/src/gestures/tap.dart 654:11                                          handleTapUp
packages/flutter/src/gestures/tap.dart 311:5                                           [_checkUp]
packages/flutter/src/gestures/tap.dart 244:7                                           handlePrimaryPointer
packages/flutter/src/gestures/recognizer.dart 630:9                                    handleEvent
packages/flutter/src/gestures/pointer_router.dart 98:12                                [_dispatch]
packages/flutter/src/gestures/pointer_router.dart 143:9                                <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart 21:13               forEach
packages/flutter/src/gestures/pointer_router.dart 141:17                               [_dispatchEventToRoutes]
packages/flutter/src/gestures/pointer_router.dart 127:7                                route
packages/flutter/src/gestures/binding.dart 488:19                                      handleEvent
packages/flutter/src/gestures/binding.dart 468:14                                      dispatchEvent
packages/flutter/src/rendering/binding.dart 333:11                                     dispatchEvent
packages/flutter/src/gestures/binding.dart 413:7                                       [_handlePointerEventImmediately]
packages/flutter/src/gestures/binding.dart 376:5                                       handlePointerEvent
packages/flutter/src/gestures/binding.dart 323:7                                       [_flushPointerEventQueue]
packages/flutter/src/gestures/binding.dart 292:9                                       [_handlePointerDataPacket]
lib/_engine/engine/platform_dispatcher.dart 1319:13                                    invoke1
lib/_engine/engine/platform_dispatcher.dart 303:5                                      invokeOnPointerDataPacket
lib/_engine/engine/pointer_binding.dart 168:39                                         [_onPointerData]
lib/_engine/engine/pointer_binding.dart 791:20                                         <fn>
lib/_engine/engine/pointer_binding.dart 720:14                                         <fn>
lib/_engine/engine/pointer_binding.dart 317:16                                         loggedHandler
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 574:37       _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 579:39       dcall
Handler: "onTap"
Recognizer: TapGestureRecognizer#c150a
  debugOwner: GestureDetector
  state: possible
  won arena
  finalPosition: Offset(320.8, 411.0)
  finalLocalPosition: Offset(20.8, 15.1)
  button: 1
  sent tap down
====================================================================================================

相关代码

图片选择弹窗函数

File? pickedImage;

void imagePickerOption() {
  Get.bottomSheet(
    SingleChildScrollView(
      child: ClipRRect(
        borderRadius: const BorderRadius.only(
          topLeft: Radius.circular(10.0),
          topRight: Radius.circular(10.0),
        ),
        child: Container(
          color: Colors.white,
          height: 250,
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                const Text(
                  "Select Image From",
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                  textAlign: TextAlign.center,
                ),
                const SizedBox(
                  height: 10,
                ),
                ElevatedButton.icon(
                  onPressed: () async {
                    pickImage(
                      ImageSource.camera,
                    );
                  },
                  icon: const Icon(
                    Icons.camera,
                    color: Colors.white,
                  ),
                  label: const Text(
                    "CAMERA",
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                ),
                const SizedBox(
                  height: 10,
                ),
                ElevatedButton.icon(
                  onPressed: () async {
                    pickImage(
                      ImageSource.gallery,
                    );
                  },
                  icon: const Icon(
                    Icons.image,
                    color: Colors.white,
                  ),
                  label: const Text(
                    "GALLERY",
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                ),
                const SizedBox(
                  height: 10,
                ),
                ElevatedButton.icon(
                  onPressed: () {
                    Get.back();
                  },
                  icon: const Icon(
                    Icons.close,
                    color: Colors.white,
                  ),
                  label: const Text(
                    "CANCEL",
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    ),
  );
}

图片选择函数

void pickImage(ImageSource imageType) async {
  try {
    final photo = await ImagePicker().pickImage(source: imageType);
    if (photo == null) return;
    final tempImage = File(photo.path);
    setState(() {
      pickedImage = tempImage;
    });
    Get.back();
  } catch (error) {
    debugPrint(error.toString());
  }
}

InkWell所在布局代码

Stack(
  children: [
    Container(
      width: 120,
      height: 120,
      decoration: BoxDecoration(
        border: Border.all(
          width: 4,
          color: Theme.of(context).scaffoldBackgroundColor,
        ),
        boxShadow: [
          BoxShadow(
            spreadRadius: 2,
            blurRadius: 10,
            color: Colors.black.withOpacity(0.1),
            offset: const Offset(0, 10),
          )
        ],
        shape: BoxShape.circle,
      ),
      child: ClipOval(
        child: Image.network(
          profilePicture,
          width: 120,
          height: 120,
          fit: BoxFit.cover,
        ),
      ),
    ),
    Positioned(
      bottom: 0,
      right: 0,
      child: InkWell(
        onTap: imagePickerOption,
        child: Container(
          height: 40,
          width: 40,
          decoration: BoxDecoration(
            shape: BoxShape.circle,
            border: Border.all(
              width: 4,
              color:
                  Theme.of(context).scaffoldBackgroundColor,
            ),
            color: const Color(0XFF00B251),
          ),
          child: const Icon(
            Icons.edit_outlined,
            color: Colors.white,
          ),
        ),
      ),
    ),
  ],
),

错误原因分析

从错误栈可定位,空值错误发生在GetX的ExtensionBottomSheet.bottomSheet方法内部的空值检查,核心原因是GetX无法获取有效导航上下文:

  • 项目根组件使用普通MaterialApp而非GetX要求的GetMaterialApp,导致GetX无法初始化导航上下文。
  • 调用Get.bottomSheet时未传入有效context参数。

修复方案

方案1:替换根组件为GetMaterialApp

将项目入口的MaterialApp替换为GetMaterialApp,确保GetX能正确管理全局导航上下文:

void main() {
  runApp(const GetMaterialApp(
    home: YourHomePage(),
  ));
}

方案2:手动传入context调用Get.bottomSheet

若无法替换根组件,调用Get.bottomSheet时手动传入当前页面的context:

void imagePickerOption(BuildContext context) {
  Get.bottomSheet(
    // 原有弹窗内容
    context: context,
  );
}

// 修改InkWell的onTap:
InkWell(
  onTap: () => imagePickerOption(context),
  // 其他代码
)

额外检查

确认profilePicture变量不为空字符串,避免Image.network加载空URL引发潜在错误。

内容的提问来源于stack exchange,提问作者Mr Fin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 13:07:04