Using Overlay in Flutter to pass in context prompt: Null check operator used on a null value (null check operator used on a null value)

First of all, the GetX framework is used at this time. The screenshot of the framework is as follows:

The code in View is as follows:

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 code

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();
  }
}

The use of Overlay encapsulates a separate class PopToastManager(). The code of PopToastManager() is as follows:

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;
    }
  }
}

The running results are as follows:

 According to the printed statement, the code does not start building OverlayEntry(builder:(context){}) at all

Check the error and find that the problem occurs in the judgment of the null value of context in Overlay.of(context)!.insert(overlayEntry);

1. So I first added a judgment on whether the context is empty in the PopToastManager() class buildUI() method.

 

The result of running at this time

Note: The context passed in at this time is not empty but Overlay.of(context) is empty.

Why is this happening?

First of all: need to knowWhat does Overlay.of(context) mean?

Data search:Overlay is a special Widget that can display floating elements in an application. Overlay.of(context) is a method in the Flutter framework, used to obtain the nearest Overlay in the specified context. The object returned by the Overlay.of(context) method can be used to add floating elements to the Overlay.

If Overlay.of(context) returns null, it means that the Overlay was not found in the specified context. This is usually caused by not adding an Overlay to the context's Widget tree. Before using Overlay.of(context), you need to make sure you have an Overlay added to your application's Widget tree.

At this point it can be inferred:

1. There is no Overlay added in the context, so the floating element x cannot be added to the Overlay.

2. There is a problem with the context

 Try to solve the problem (1):

 

 Reason for error:

1. In Flutter, context is a very important concept, which represents the position of the widget in the widget tree. The difference in context may affect the widgets or state you can access.

2. Get.context is used when passing context in the code. Get is a library for state management and dependency injection. Its context is global and may not be in the widget tree of your current widget. Therefore, when you use Get.context, you may get a global context that is not in the current widget tree.


3. But Overlay.of(context) requires a context in the current widget tree to work properly. If the context you pass in is not in the current widget tree, Overlay.of(context) will return null.

4. Therefore, even if Get.context is not null, Overlay.of(Get.context) may be null because Get.context may not be in the current widget tree.

To solve this problem, you need to ensure that the context you pass into Overlay.of(context) is in the current widget tree.

Pass context as a parameter into selectTypePop()

 

Guess you like

Origin blog.csdn.net/weixin_43244083/article/details/131471321