Flutter表单管理插件cubit_form的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter表单管理插件cubit_form的使用

cubit_form 是一个使用 cubit 实现的简单表单管理解决方案。它可以帮助你更方便地管理和验证表单数据。本文将通过一个完整的示例来介绍如何使用 cubit_form 插件。

安装

首先,在你的 pubspec.yaml 文件中添加 cubit_form 依赖:

dependencies:
  flutter:
    sdk: flutter
  cubit_form: ^最新版本

然后运行 flutter pub get 来安装依赖。

示例代码

以下是一个完整的示例,展示了如何使用 cubit_form 管理表单:

1. 创建表单逻辑

首先,创建一个继承自 SinglePageFormCubit 的类来管理表单字段和验证规则:

import 'dart:async';

import 'package:cubit_form/cubit_form.dart';
import 'package:flutter/material.dart';

abstract class Real extends SinglePageFormCubit {
  Real() : super() {
    login = FieldCubit<String>(
      initialValue: 'Initial value',
      validations: [
        RequiredStringValidation('required'),
        ValidationModel((value) => value.length < 3, 'too small'),
        ValidationModel((value) => value.length > 20, 'too big'),
      ],
    )..stream.listen((_) {
        password.errorCheck();
      });

    password = FieldCubit<String>(
      initialValue: '',
      validations: [
        RequiredStringValidation('required'),
        ValidationModel((value) => value.length < 3, 'too small'),
        ValidationModel((value) => value == login.state.value, 'same as login'),
      ],
    );

    zipCodeFormater = MaskTextInputFormatter(
      initialText: '1234-123',
      mask: '#####-####',
      filter: {"#": RegExp(r'[0-9]')},
    );

    zipCode = FieldCubit(
      initialValue: zipCodeFormater.getMaskedText(),
      validations: [
        RequiredStringValidation('Required'),
        RegExpValidation(
          RegExp(r'^(^\d{5}$)|(^\d{5}-\d{4}$)'),
          'should be 4 or 9 digits',
        ),
      ],
    );

    number = FieldCubit(
      initialValue: 100,
      validations: [RequiredIntValidation('required')],
    );
    var fields = [login, password, zipCode, number];
    addFields(fields);
  }

  late FieldCubit<String> login;
  late FieldCubit<String> password;
  late MaskTextInputFormatter zipCodeFormater;
  late FieldCubit<String> zipCode;
  late FieldCubit<int> number;

  @override
  FutureOr<bool> asyncValidation() {
    // login.setError('here async error');
    return true;
  }
}

class RealChild extends Real {
  RealChild() {
    string = FieldCubit<String>(
      initialValue: 'aaa',
      validations: [
        RequiredStringValidation('required'),
      ],
    );
    var fields = [string];

    addFields(fields);
  }

  @override
  void onSubmit() async {
    print('===start===');
    await Future.delayed(Duration(seconds: 2));
    print(login.state.value);
    print(password.state.value);
    print(string.state.value);

    for (var f in fields) {
      f.reset();
    }
  }

  void setString() {
    string.externalSetValue('bbb');
  }

  @override
  reset() {
    for (var f in fields) {
      f.reset();
    }
  }

  late FieldCubit<String> string;
}

2. 创建UI

接下来,创建一个 MyAppMyHomePage 来展示表单:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:cubit_form/cubit_form.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: BlocProvider<RealChild>(
          create: (_) => RealChild(),
          child: Builder(builder: (context) {
            var formCubit = context.watch<RealChild>();
            return SingleChildScrollView(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 40),
                    child: Text('''
  validation rules:
  - login must be longer than 3 symbols and shorter than 10
  - password must be longer than 3 symbols and not the same as login
                      '''),
                  ),
                  Text(formCubit.login.state.value),
                  CubitFormTextField(
                    formFieldCubit: formCubit.login,
                    decoration: InputDecoration(
                      hintText: 'name',
                      labelText: 'login',
                    ),
                  ),
                  CubitFormIntField(
                    formFieldCubit: formCubit.number,
                    decoration: InputDecoration(
                      hintText: 'number',
                      labelText: 'count',
                    ),
                  ),
                  CubitFormTextField(
                    formFieldCubit: formCubit.password,
                    obscureText: true,
                    decoration: InputDecoration(
                      hintText: 'another text',
                      labelText: 'password',
                    ),
                  ),
                  CubitFormMaskedTextField(
                    formFieldCubit: formCubit.zipCode,
                    decoration: InputDecoration(
                        labelText: 'zipCode', helperText: 'zipCode'),
                    maskFormatter: formCubit.zipCodeFormater,
                  ),
                  CubitFormTextField(
                    cursorColor: Colors.red,
                    formFieldCubit: formCubit.string,
                    decoration: InputDecoration(
                      hintText: 'another string',
                      labelText: 'string',
                      suffixIcon: Padding(
                        padding: const EdgeInsets.only(right: 8),
                        child: IconButton(
                          icon: Icon(
                            Icons.refresh,
                          ),
                          onPressed: () => formCubit.setString(),
                        ),
                      ),
                    ),
                  ),
                  if (formCubit.state.hasErrorToShow)
                    Center(
                      child: _Error(
                        child: Text('Not valid'),
                      ),
                    ),
                  Text(formCubit.state.isInitial ? "initial" : 'changed'),
                  if (!formCubit.state.hasErrorToShow)
                    Center(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceAround,
                        children: [
                          ElevatedButton(
                            child: Text(formCubit.state.isSubmitting
                                ? 'Submitting'
                                : 'Submit'),
                            onPressed: formCubit.state.isSubmitting
                                ? null
                                : () => formCubit.trySubmit(),
                          ),
                          ElevatedButton(
                            child: Text('Reset'),
                            onPressed: () => formCubit.reset(),
                          ),
                        ],
                      ),
                    )
                ],
              ),
            );
          }),
        ),
      ),
    );
  }
}

class _Error extends StatelessWidget {
  const _Error({
    Key? key,
    required this.child,
  }) : super(key: key);

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Material(
      elevation: 2,
      child: Container(
        constraints: BoxConstraints(minWidth: 88.0, minHeight: 36.0),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(3),
          color: Colors.red,
        ),
        child: Center(
          widthFactor: 1.0,
          heightFactor: 1.0,
          child: child,
        ),
      ),
    );
  }
}

3. 运行应用

现在,你可以运行你的 Flutter 应用程序来查看表单管理的效果。确保所有依赖项都已正确安装,并且没有语法错误。

flutter run

总结

通过上述示例,你可以看到 cubit_form 插件如何帮助你管理和验证表单数据。它提供了丰富的功能,如字段验证、异步验证、字段重置等,使得表单管理变得更加简单和高效。希望这个示例对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言。


更多关于Flutter表单管理插件cubit_form的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter表单管理插件cubit_form的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter中使用cubit_form插件进行表单管理的代码示例。cubit_form是一个用于处理Flutter表单状态的Cubit库,它使得状态管理和表单验证变得更加简单。

首先,确保你已经在pubspec.yaml文件中添加了cubit_formflutter_bloc的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^8.0.0  # 请使用最新版本
  cubit_form: ^0.1.0    # 请使用最新版本,注意版本号可能有所不同

然后,运行flutter pub get来安装这些依赖。

接下来,我们将创建一个简单的登录表单示例,其中包括用户名和密码字段,以及提交按钮。

1. 定义表单状态

首先,我们需要定义一个表单状态类,它将包含我们的表单字段和验证规则。

import 'package:cubit_form/cubit_form.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

part 'login_form_state.dart';

class LoginFormCubit extends Cubit<FormState<LoginFormState>> {
  LoginFormCubit() : super(FormState<LoginFormState>(LoginFormState()));

  void usernameChanged(String value) {
    emit(state.copyWith(
      username: FormFieldState<String>(value: value, validators: [requiredValidator]),
    ));
  }

  void passwordChanged(String value) {
    emit(state.copyWith(
      password: FormFieldState<String>(value: value, validators: [requiredValidator, minLengthValidator(6)]),
    ));
  }

  void submitted() {
    emit(state.copyWith(
      status: FormStatus.submitting,
    ));
    final isValid = state.validate();
    if (isValid) {
      // Handle successful submission
      emit(state.copyWith(status: FormStatus.submitted));
    } else {
      emit(state.copyWith(status: FormStatus.error));
    }
  }
}

在上面的代码中,我们定义了一个LoginFormCubit,它继承自Cubit并持有FormState<LoginFormState>作为状态。LoginFormState类定义表单字段的状态,这里我们定义了usernamepassword字段,并为它们设置了验证规则。

2. 定义表单字段状态

接下来,我们定义LoginFormState类,它将包含表单字段的状态。

// login_form_state.dart

part of 'login_form_cubit.dart';

class LoginFormState {
  final FormFieldState<String> username;
  final FormFieldState<String> password;

  LoginFormState({
    required this.username,
    required this.password,
  });

  LoginFormState copyWith({
    FormFieldState<String>? username,
    FormFieldState<String>? password,
  }) {
    return LoginFormState(
      username: username ?? this.username,
      password: password ?? this.password,
    );
  }
}

3. UI 层

最后,我们在UI层使用BlocBuilderBlocProvider来连接我们的Cubit和UI组件。

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'login_form_cubit.dart';

void main() {
  runApp(MultiBlocProvider(
    providers: [
      BlocProvider(create: (_) => LoginFormCubit()),
    ],
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: LoginScreen(),
    );
  }
}

class LoginScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Login')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: BlocListener<LoginFormCubit, FormState<LoginFormState>>(
          listener: (context, state) {
            if (state.status == FormStatus.submitted) {
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Login Successful')));
            } else if (state.status == FormStatus.error) {
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Please fix the errors')));
            }
          },
          child: Column(
            children: <Widget>[
              TextField(
                decoration: InputDecoration(labelText: 'Username'),
                onChanged: (value) => context.read<LoginFormCubit>().usernameChanged(value),
                controller: TextEditingController(text: state.username.value), // 需要手动管理控制器以显示当前值
              ),
              TextField(
                decoration: InputDecoration(labelText: 'Password'),
                obscureText: true,
                onChanged: (value) => context.read<LoginFormCubit>().passwordChanged(value),
                controller: TextEditingController(text: state.password.value), // 需要手动管理控制器以显示当前值
              ),
              SizedBox(height: 24),
              ElevatedButton(
                onPressed: () => context.read<LoginFormCubit>().submitted(),
                child: Text('Login'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

注意:由于TextFieldcontroller属性在cubit_form的使用中并不是直接支持的,上面的代码示例中手动管理了TextEditingController来显示当前值,但在实际使用中,你可能需要找到一种方法来同步cubit状态和TextField的显示,这通常涉及到在表单状态改变时更新控制器,以及在控制器内容改变时更新cubit状态。这可以通过监听控制器的变化或在需要时手动同步状态来实现。

这个示例展示了如何使用cubit_form库进行基本的表单管理和验证。根据你的具体需求,你可能需要调整状态管理和验证逻辑。

回到顶部