6

这是我的更改密码屏幕。我正在使用 flutter_bloc 来实现 mvvc 模式。此页面适用于 bloc。但我想要实现的是在提交表单时验证表单。由于我是新手,所以我不知道该怎么做。

更改密码事件

abstract class ChangePasswordEvent extends Equatable {
  const ChangePasswordEvent();
}

class SubmitButtonPressed extends ChangePasswordEvent {
  final String oldPassword;
  final String newPassword;

  const SubmitButtonPressed({@required this.oldPassword, this.newPassword});

  @override
  List<Object> get props => [oldPassword, newPassword];
}

更改密码状态

abstract class ChangePasswordState extends Equatable {
  const ChangePasswordState();

  @override
  List<Object> get props => [];
}

class ChangePasswordInitial extends ChangePasswordState {}

class ChangePasswordLoading extends ChangePasswordState {}

class ChangePasswordSuccess extends ChangePasswordState {}

class ChangePasswordFailure extends ChangePasswordState {
  final String error;

  const ChangePasswordFailure({@required this.error});

  @override
  List<Object> get props => [error];

  @override
  String toString() => 'ChangePasswordFailure { error: $error }';
}

更改密码块

class ChangePasswordBloc
    extends Bloc<ChangePasswordEvent, ChangePasswordState> {
  final UserRepository userRepository;

  ChangePasswordBloc({
    @required this.userRepository,
  }) : assert(userRepository != null);

  @override
  ChangePasswordState get initialState => ChangePasswordInitial();

  @override
  Stream<ChangePasswordState> mapEventToState(
      ChangePasswordEvent event) async* {
    if (event is SubmitButtonPressed) {
      yield ChangePasswordLoading();

      try {
        final bool isPasswordChanged = await userRepository.changePassword(
          event.oldPassword,
          event.newPassword,
        );

        if (isPasswordChanged) {
          yield ChangePasswordSuccess();
        }
      } catch (error) {
        yield ChangePasswordFailure(error: error);
      }
    }
  }
}

更改密码页面

class ChangePasswordPage extends StatelessWidget {
  final UserRepository userRepository;

  ChangePasswordPage({Key key, @required this.userRepository})
      : assert(userRepository != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Change Password'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: BlocProvider(
          create: (context) {
            return ChangePasswordBloc(
              userRepository: userRepository,
            );
          },
          child: ChangePasswordForm(),
        ),
      ),
    );
  }
}

更改密码表格

class ChangePasswordForm extends StatefulWidget {
  @override
  _ChangePasswordFormState createState() => _ChangePasswordFormState();
}

class _ChangePasswordFormState extends State<ChangePasswordForm> {
  final userRepository = UserRepository();
  final _formKey = GlobalKey<FormState>();

  final _oldPassController = TextEditingController();
  final _newPassController = TextEditingController();
  final _confirmPassController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    _onSubmitButtonPressed() {
      BlocProvider.of<ChangePasswordBloc>(context).add(
        SubmitButtonPressed(
          oldPassword: _oldPassController.text,
          newPassword: _newPassController.text,
        ),
      );
    }

    return BlocListener<ChangePasswordBloc, ChangePasswordState>(
      listener: (context, state) {
        if (state is ChangePasswordFailure) {
          Scaffold.of(context).showSnackBar(
            SnackBar(
              content: Text('${state.error}'),
              backgroundColor: Colors.red,
            ),
          );
        }

        if (state is ChangePasswordSuccess) {
          Scaffold.of(context).showSnackBar(
            SnackBar(
              content: Text('Password Changed Successfully'),
              backgroundColor: Colors.green,
            ),
          );
        }
      },
      child: BlocBuilder<ChangePasswordBloc, ChangePasswordState>(
        builder: (context, state) {
          return Form(
            key: _formKey,
            child: Column(
              children: [
                TextFormField(
                  decoration: InputDecoration(labelText: 'Old Password'),
                  controller: _oldPassController,
                ),
                SizedBox(height: 20.0),
                TextFormField(
                  decoration: InputDecoration(labelText: 'New Password'),
                  controller: _newPassController,
                  obscureText: true,
                ),
                SizedBox(height: 20.0),
                TextFormField(
                  decoration: InputDecoration(labelText: 'Confirm Password'),
                  controller: _confirmPassController,
                  obscureText: true,
                  validator: (value) {
                    final String _newPassword = _newPassController.text;

                    if (_newPassword != value) {
                      return "Password Mismatch";
                    }

                    return null;
                  },
                ),
                SizedBox(height: 20.0),
                RaisedButton(
                  onPressed: () {
                    if (state is! ChangePasswordLoading) {
                      final form = _formKey.currentState;

                      if (form.validate()) {
                        return _onSubmitButtonPressed();
                      }

                      return null;
                    }
                  },
                  child: Text('Submit'),
                ),
              ],
            ),
          );
        },
      ),
    );
  }
}
4

2 回答 2

8

你去看看他们的例子:表单验证

该示例验证电子邮件和密码格式,您应该相应地更改它。你的状态应该是这样的:

class MyFormState extends Equatable {
  final String email;
  final bool isEmailValid;
  final String password;
  final bool isPasswordValid;
  final bool formSubmittedSuccessfully;

  bool get isFormValid => isEmailValid && isPasswordValid;
  //....
}

BLoC 验证:

class MyFormBloc extends Bloc<MyFormEvent, MyFormState> {
  final RegExp _emailRegExp = RegExp(
    r'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
  );
  final RegExp _passwordRegExp = RegExp(
    r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$',
  );

  @override
  MyFormState get initialState => MyFormState.initial();

  @override
  void onTransition(Transition<MyFormEvent, MyFormState> transition) {
    print(transition);
  }

  @override
  Stream<MyFormState> mapEventToState(
    MyFormEvent event,
  ) async* {
    if (event is EmailChanged) {
      yield state.copyWith(
        email: event.email,
        isEmailValid: _isEmailValid(event.email),
      );
    }
    if (event is PasswordChanged) {
      yield state.copyWith(
        password: event.password,
        isPasswordValid: _isPasswordValid(event.password),
      );
    }
    if (event is FormSubmitted) {
      yield state.copyWith(formSubmittedSuccessfully: true);
    }
    if (event is FormReset) {
      yield MyFormState.initial();
    }
  }

  bool _isEmailValid(String email) {
    return _emailRegExp.hasMatch(email);
  }

  bool _isPasswordValid(String password) {
    return _passwordRegExp.hasMatch(password);
  }
}

和 Form 构建方法:

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<MyFormBloc, MyFormState>(
      builder: (context, state) {
        if (state.formSubmittedSuccessfully) {
          return SuccessDialog(onDismissed: () {
            _emailController.clear();
            _passwordController.clear();
            _myFormBloc.add(FormReset());
          });
        }
        return Form(
          child: Column(
            children: <Widget>[
              TextFormField(
                controller: _emailController,
                decoration: InputDecoration(
                  icon: Icon(Icons.email),
                  labelText: 'Email',
                ),
                keyboardType: TextInputType.emailAddress,
                autovalidate: true,
                validator: (_) {
                  return state.isEmailValid ? null : 'Invalid Email';
                },
              ),
              TextFormField(
                controller: _passwordController,
                decoration: InputDecoration(
                  icon: Icon(Icons.lock),
                  labelText: 'Password',
                ),
                obscureText: true,
                autovalidate: true,
                validator: (_) {
                  return state.isPasswordValid ? null : 'Invalid Password';
                },
              ),
              RaisedButton(
                onPressed: state.isFormValid ? _onSubmitPressed : null,
                child: Text('Submit'),
              ),
            ],
          ),
        );
      },
    );
  }
于 2020-04-10T11:52:44.323 回答
1

我认为最好不要将 flutter_bloc 包用于验证目的,因为它会导致所有控件的重建。而是使用像这里描述的 Stream 和 Provider 这样的原始对象。 https://www.youtube.com/watch?v=JqWK4oitJFs

附加链接:https ://medium.com/swlh/how-to-create-a-simple-login-form-in-flutter-using-bloc-pattern-b55ad52a2a10

于 2020-06-24T09:33:22.000 回答