得到了NoSuchMethodError(NoSuchMethodError:方法'call'在null上被调用。

时间:2020-10-07 18:05:18

标签: flutter

我有一个包含表单小部件的“表单”屏幕。 更改状态后(现在使用bloc但我使用setState进行了测试,没什么不同),出现以下错误:

The following NoSuchMethodError was thrown while handling a gesture:
The method 'call' was called on null.
Receiver: null
Tried calling: call()

这仅在我更改状态时发生(如果我不产生新状态或setState,则它可以正常工作而没有错误)。 但是在更改状态并可能重建了小部件之后,我得到了错误:

这是主屏幕:

class _AuthScreenState extends State<AuthScreen> {
  final AuthRepository repository = AuthRepository();
  PageController controller;
  Bloc _bloc;

  @override
  void initState() {
    controller = PageController(initialPage: widget.page);
    super.initState();
  }

  void changePage(int page) {
    controller.animateToPage(
      page,
      curve: Curves.ease,
      duration: Duration(milliseconds: 300),
    );
  }

  void onSubmit(AuthType authType, AuthReq req) {
    if (authType == AuthType.LOGIN) {
      _bloc.add(LoginEvent(req: req));
    } else {
      _bloc.add(RegisterEvent(req: req));
    }
  }

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (ctx) => AuthBloc(repository: repository),
      child: BlocBuilder<AuthBloc, AuthState>(
        builder: (context, state) {
          _bloc = context.bloc<AuthBloc>();
          return ScreenContainer(
            loading: state is LoadingState,
            child: Container(
              width: double.infinity,
              height: double.infinity,
              child: Column(
                children: [
                  Expanded(
                    child: PageView.builder(
                      controller: controller,
                      physics: NeverScrollableScrollPhysics(),
                      itemCount: 2,
                      itemBuilder: (context, position) {
                        return position == 0
                            ? LoginPage(
                                onPageChange: () => changePage(1),
                                onSubmit: (req) => onSubmit(AuthType.LOGIN, req),
                              )
                            : RegisterPage(
                                onPageChange: () => changePage(0),
                                onSubmit: (req) => onSubmit(AuthType.REGISTER, req),
                              );
                      },
                    ),
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }
}
class LoginPage extends StatelessWidget {
  final VoidCallback onPageChange;
  final void Function(AuthReq req) onSubmit;
  final FormController controller = FormController();
  LoginPage({
    @required this.onPageChange,
    @required this.onSubmit,
  });

  void submit() {
    var values = controller?.submit();
    if (values.isNull) {
      return;
    }
    onSubmit(AuthReq(password: values['password'], username: values['email']));
  }

  @override
  Widget build(BuildContext context) {
    var authType = AuthType.LOGIN;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Expanded(
          child: Padding(
            padding: EdgeInsets.symmetric(horizontal: hP),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Expanded(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      FormWrapper(
                        inputs: loginFields,
                        controller: controller,
                      ),
                      submitButton(context, authType, submit),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
}
class FormController {
  Map Function() submit;
}

class FormWrapper extends StatefulWidget {
  final List<InputProps> inputs;
  final FormController controller;
  FormWrapper({
    @required this.inputs,
    this.controller,
  });
  @override
  _FormWrapperState createState() => _FormWrapperState(controller);
}

class _FormWrapperState extends State<FormWrapper> {
  final _formKey = GlobalKey<FormState>();
  _FormWrapperState(FormController _controller) {
    _controller.submit = submit;
  }

  bool _autoValidation = false;
  Map values = {};

  void setValue(String key, dynamic value) {
    values[key] = value;
  }

  Map submit() {
    if (_formKey.currentState.validate()) {
      _formKey.currentState.save();
      return values;
    } else {
      setState(() {
        _autoValidation = true;
      });
      return null;
    }
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Form(
        autovalidate: _autoValidation,
        key: _formKey,
        child: Column(
          children: widget.inputs
              .map(
                (e) => Container(
                  margin: EdgeInsets.only(bottom: e.isLast ? 0 : 24.0 - 7.0),
                  child: RoundedInput(
                    inputProps: e,
                    onChange: (value) => setValue(e.label, value),
                  ),
                ),
              )
              .toList(),
        ),
      ),
    );
  }
}

1 个答案:

答案 0 :(得分:0)

我找到了解决方案,我发布答案而不是删除问题,以免将来可能对其他人有所帮助:)

我覆盖 didUpdateWidget 以重新初始化 _FormWrapperState 中的变量:

  @override
  void didUpdateWidget(oldWidget) {
    widget.controller.submit = submit;
    super.didUpdateWidget(oldWidget);
  }