Flutter中使用Overlay传入context提示:Null check operator used on a null value(对空值使用空检查运算符)

首先此时使用的是GetX框架,框架截图如下:

View中代码如下:

class AddTaskPage extends StatelessWidget {
  const AddTaskPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final logic = Get.put(AddTaskLogic());
    final state = Get.find<AddTaskLogic>().state;

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Tcolor.barBackgroudColor,
        elevation: 0,
      ),
      body: _addTaskContent(state),
    );
  }

  _addTaskContent(AddTaskState addTaskState) {
    return GetBuilder<AddTaskLogic>(builder: (logic) {
      return Container(
        child: Column(
          children: [
            //任务类型 0-工作 1-学习 2-生活
            Container(
              key: logic.typeKey,
              child: InputFied(
                  fieldwidth: 300,
                  hintText: "请选择任务类型",
                  controller: addTaskState.contentController,
                  iconWidget: InkWell(
                    child: Icon(addTaskState.typeExpand?Icons.expand_less_outlined:Icons.expand_more,color: Colors.grey,size: 18,),
                    onTap: (){
                      print("弹出任务类型选择框");
                      logic.selectTypePop();
                    },
                  )
              ),
            ),
          ],
        ),
      );
    });
  }
}

logic代码

class AddTaskLogic extends GetxController {
  final AddTaskState state = AddTaskState();
  GlobalKey typeKey = GlobalKey();
  //弹出任务类型选择框
  selectTypePop(){
    state.typeExpand=!state.typeExpand;
    update();
    RenderBox typeBox = typeKey.currentContext!.findRenderObject() as RenderBox;
    print("要开始构建了Pop了");
    
    PopToastManager().buildUI(
      context: Get.context!,
      isClickDiss: true,
      X: typeBox.localToGlobal(Offset.zero).dx + 28 + 76,
      Y: typeBox.localToGlobal(Offset.zero).dy + 26,
      offx: 0,
      offy: 0,
      width: 260,
      height: 90,
      childWidget: ListView.builder(
        itemCount: state.taskType.length,
        itemBuilder: (context, index) {
          print("构建UI");
          return Container(
            child: Row(
              children: [
                ClipRRect(
                  borderRadius: BorderRadius.circular(60),
                  child: Container(
                    width: 13,
                    height: 13,
                    decoration: BoxDecoration(
                      color: state.typeColor[index],
                    ),
                  ),
                ),
                SizedBox(width: 20,),
                Text(state.taskType[index]),
              ],
            ),
          );
        },
      ),
    );
    update();
  }
}

对Overlay的使用封装了一个单独的类PopToastManager(),PopToastManager()代码如下:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

//封装一个构造弹窗类
/*OverlayEntry 可以实现悬浮窗效果*/
class PopToastManager{

  /*OverlayEntry类型的私有实例变量*/
  OverlayEntry? _overlayEntry;
  /*PopToastManager类型的私有实例变量*/
  static PopToastManager? _manager;
  /*PopToastManager的私有构造函数,用于创建新实例*/
  PopToastManager._();
  /*PopToastManager的工厂构造函数,用于创建类的实例,并保证只创建一个实例*/
  factory PopToastManager(){
    if(_manager==null){
      _manager=PopToastManager._();
    }
    return _manager!;
  }

  /*在buildUI()函数内部创建overlayEntry对象并且插入到overlayEntry中*/
  void buildUI(
      {
        required BuildContext context,
        required bool isClickDiss,
        required double X,
        required double Y,
        required double offx,
        required double offy,
        required double width,
        required double height,
        required Widget childWidget,
        Function? dismissCallBack/*取消的回调函数*/
      }){

    //创建 overlayEntry
    OverlayEntry overlayEntry=OverlayEntry(

        builder: (context){
          print("开始构建overlayEntry");
          return GestureDetector(
            behavior:HitTestBehavior.opaque ,
            /*点击事件*/
            onTap: (){
              /*如果可以点击*/
              if(isClickDiss){
                /*取消回调函数不为空则调用取消回调函数*/
                if (dismissCallBack != null) {
                  dismissCallBack();
                }
                /*蒙层取消函数*/
                dissmiss();
              }
            },
            /*子组件*/
            child: Container(
              width: MediaQuery.of(context).size.width,
              height: MediaQuery.of(context).size.height,
              color: Colors.transparent,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  // Container(height: Y,),
                  SizedBox(height: Y,),
                  Container(
                    margin: EdgeInsets.fromLTRB(offx + X,offy, 0, 0),
                    width: width,
                    height: height,
                    child: childWidget,
                  ),
                ],
              ),
            ),
          );
        });
    this._overlayEntry = overlayEntry;
    //插入到 Overlay中显示 OverlayEntry
    Overlay.of(context)!.insert(overlayEntry);
    /*final overlay = Overlay.of(context);
    if (overlay != null) {
      overlay.insert(overlayEntry);
    } else {
      print('Overlay is null');
    }*/
  }


  void dissmiss(){
    if(this._overlayEntry != null){
      print("蒙层消失");
      this._overlayEntry!.remove();
      this._overlayEntry = null;
    }
  }
}

运行结果如下:

 根据打印的语句可以得知,代码根本没有开始构建OverlayEntry(builder:(context){})

查看错误,发现问题出现在对Overlay.of(context)!.insert(overlayEntry);中context的空值判断

1、于是我首先在PopToastManager()类buildUI()方法中添加对context是否为空的判断

此时运行结果

说明:此时传入的context不为空但是Overlay.of(context)为空

为什么会这样?

首先:需要知道Overlay.of(context)意味着什么?

据搜索Overlay 是一个可以在应用程序中显示浮动元素的特殊 Widget。Overlay.of(context)是Flutter框架中的一个方法,用于获取指定上下文中最近的Overlay,Overlay.of(context) 方法返回的对象可以用于向 Overlay 中添加浮动元素。

如果 Overlay.of(context) 返回 null,则表示指定上下文中没有找到 Overlay。这通常是由于没有在该上下文的 Widget 树中添加 Overlay 导致的。在使用 Overlay.of(context) 之前,需要确保在应用程序的 Widget 树中添加了 Overlay。

此时可推测:

1、在上下文中没有添加Overlay,所以不能向Overlay 中添加浮动元素x

2、上下文出现了问题

 试解决问题(1):

 出错的原因:

1、在 Flutter 中,context 是一个非常重要的概念,它代表了 widget 在 widget 树中的位置。context 的不同,可能会影响到你能够访问到的 widget 或者 state。

2、在代码中传入context时使用了 Get.context。Get 是一个用于状态管理和依赖注入的库,它的 context 是全局的,可能并不在你当前 widget 的 widget 树中。因此,当你使用 Get.context 时,你可能得到的是一个全局的、不在当前 widget 树中的 context。


3、但是 Overlay.of(context) 需要一个在当前 widget 树中的 context 才能正常工作。如果你传入的 context 不在当前 widget 树中,Overlay.of(context) 就会返回 null。

4、所以,即使 Get.context 不为 null,Overlay.of(Get.context) 也可能为 null,因为 Get.context 可能不在当前 widget 树中。

要解决这个问题,你需要确保你传入 Overlay.of(context) 的 context 是在当前 widget 树中的。

将context作为参数传入进selectTypePop()

猜你喜欢

转载自blog.csdn.net/weixin_43244083/article/details/131471321