显示带有 BlocListener 的对话框

Showing a dialog with BlocListener

我有 2 个带有手势检测器的文本字段,点击手势检测器后,我使用 BlocListener 小部件打开了一个 AlertDialog。

Widget _getSourceAndOriginTextField(String hintText, controller) {
    final portsCubit = BlocProvider.of<PortsCubit>(context);
    return TextFormField(
      controller: controller..text = "",
      readOnly: true,
      decoration: InputDecoration(
          suffixIcon: GestureDetector(
              onTap: () {
                portsCubit.getAllPorts();
              },
              child: BlocListener<PortsCubit, PortsState>(
                listenWhen: (previous, current) => previous != current,
                listener: (context, state) async {
                  if (state is PortsLoadedState) {
                    await showDialog(
                        context: context,
                        builder: (_) => BlocProvider.value(
                              value: portsCubit,
                              child: PortsDialog(state.portsList),
                            ));
                  }
                },
                child: SvgPicture.asset(
                  'assets/svg/chevron_down_icon.svg',
                  fit: BoxFit.scaleDown,
                  height: 10,
                  width: 18,
                ),
              )),
          focusedBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(8.0),
            borderSide: BorderSide(
              color: Colors.transparent,
              style: BorderStyle.solid,
              width: 1,
            ),
          ),
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(8.0),
            borderSide: BorderSide.none,
          ),
          filled: true,
          contentPadding: EdgeInsets.all(8),
          hintText: hintText,
          hintStyle: AppStyle.hintStyle),
    );
  }

此方法上面 returns 在表单内部使用了一个 TextField 来显示两个文本字段。

Form(
    children:[_getSourceAndOriginTextField('Origin',controller),
    SizedBox(height:10),
    _getSourceAndOriginTextField('Origin',controller)])

当我点击其中一个文本字段时,状态发生变化并且对话框打开,但对话框显示了两次。我在这里错过了什么?

以下图片供参考,如有帮助将不胜感激。

TextField inside the form.

The AlertDialog

I have 2 textFields

This method above which returns a TextField is being used inside the form to display two textfields.

基本说明了你的问题。由于您正在执行 _getSourceAndOriginTextField() 两次,因此您还创建了 BlocListener<PortsCubit, PortsState>(...) 两次。因此,当 PortsCubit 状态变为 PortsLoadedState 时,两个侦听器都会触发 showDialog 函数。

你可以做的是提起 BlocListener 并用它包裹 Form。这样您将只有一个可以打开对话框的侦听器:

BlocListener<PortsCubit, PortsState>(
  listenWhen: (previous, current) => previous != current,
  listener: (context, state) async {
    if (state is PortsLoadedState) {
      await showDialog(
        context: context,
        builder: (_) => BlocProvider.value(
          value: portsCubit,
          child: PortsDialog(state.portsList),
      ));
  },
  child: Form(
    children:[_getSourceAndOriginTextField('Origin',controller),
    SizedBox(height:10),
    _getSourceAndOriginTextField('Origin',controller)]) 
},