본문 바로가기
Flutter

[flutter] PopupMenuItem 에서 dialog 여는 법

by 아마도개발자 2023. 10. 31.

아마도 flutter에서 context를 이해하는건 굉장히 멀고도 험한 길인 것 같다.

 

오늘은 PopupMenuItem를 onTap했을 때, dialog를 열어주는 부분을 구현하였다. 간단하게 onTap에 dialog를 여는 함수를 넣어주었는데, 이상하게도 print 했을 때 콘솔은 찍히는데 dialog가 열리지 않았다. 

 

await showMenu(
        context: context,
        position: RelativeRect.fromLTRB(
          offset.dx,
          offset.dy,
          MediaQuery.of(context).size.width - offset.dx,
          MediaQuery.of(context).size.height - offset.dy
        ),
        items: [
          PopupMenuItem(
            onTap: () {
            	modifyPopUp(x, y, z);
            },
            child: Text("x")
          )
        ]
    );

 

Future modifyPopUp(String x, String y, String z) async {
    print("들어오는데?");
    return await showDialog(
        context: context,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return AlertDialog(
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(10.0)),

            title: Column(
              children: <Widget>[
                new Text("수정하기"),
              ],
            ),
            //
            content: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                TextField(
                  controller: _modifyController,
                )
              ],
            ),
            actions: <Widget>[
              TextButton(
                child: new Text("확인"),
                onPressed: () {
                  modifyMemo(x, y, z, _modifyController.text);

                },
              ),
              TextButton(
                child: new Text("취소"),
                onPressed: () {
                  AppStorage.popNavigator();
                },
              ),
            ],
          );
        });
  }

한참을 고민했다. 왜 showDialog를 return하지 않을까!

 

힌트는 PopupMenuItem에 있었다.  PopupMenuItem클래스를 살펴보니

 

@protected
  void handleTap() {
    widget.onTap?.call();

    Navigator.pop<T>(context, widget.value);
  }

라는 부분이 있었고, 결국 ontap으로 item을 눌렀을 때 Navigator.pop(context)가 실행된다는 것이었다. 결국 내가 showdialog를 열더라도, Navigator.pop(context)가 실행되면서 dialog가 켜지자마자 꺼지는 바보같은 상황이 발생하는 것이다.

 

이를 해결하기위해 showdialog를 사용하는 함수 호출시에 WidgetsBinding.instance.addPostFrameCallback 를 감싸주어 성공적으로 함수를 호출 시킬 수 있었다. WidgetsBinding.instance.addPostFrameCallback로 widget이 빌드된 뒤에 콜백이 실행 될 수 있도록 한다는 의미긴 했는데.. 좀 더 공부가 필요할 것 같다.

 

최종 코드

Future<void> handleRawKeyEvent(TapDownDetails details, String x, String y, String z) async {
    print("들어는옴");
    tapDownPosition = details.globalPosition;
    final offset = details.globalPosition;
    await showMenu(
        context: context,
        position: RelativeRect.fromLTRB(
          offset.dx,
          offset.dy,
          MediaQuery.of(context).size.width - offset.dx,
          MediaQuery.of(context).size.height - offset.dy
        ),
        items: [
          PopupMenuItem(
            onTap: () {
              WidgetsBinding?.instance?.addPostFrameCallback((_) {
                modifyPopUp(x, y, z);
              });

            },
            child: Text("수정하기")
          )
        ]
    );

 

오늘도 성장했다.. 아마도