You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter求助:如何从注册子页面向引导页面传递数据

Flutter 多步骤注册页面的数据传递方案

方案一:父组件统一维护数据,子组件通过回调更新

这种方式由SignUpOnbordingScreen持有用户数据对象,子注册页面通过回调函数将输入数据同步到父组件,是最直接的状态管理方式。

步骤1:修改SignUpOnbordingScreen

在父组件中创建用户数据对象,定义对应子页面的回调函数,并传递给各子页面:

class SignUpOnbordingScreen extends StatefulWidget {
  const SignUpOnbordingScreen({Key? key}) : super(key: key);

  static const routeName = "/signUpOnbording";

  @override
  State<SignUpOnbordingScreen> createState() => _SignUpOnbordingScreenState();
}

class _SignUpOnbordingScreenState extends State<SignUpOnbordingScreen> {
  // 父组件维护完整用户数据
  final User _user = User(
    id: DateTime.now().toString(),
    email: "",
    password: "",
    passwordWiederholen: "",
    phoneNumber: "", // 对应SignUpNumbers页面字段
    socialAccount: "" // 对应SignUpSocialNetwork页面字段
  );

  // 更新邮箱密码信息的回调
  void _updateEmailData(String email, String password, String repeatPassword) {
    setState(() {
      _user.email = email;
      _user.password = password;
      _user.passwordWiederholen = repeatPassword;
    });
  }

  // 更新手机号信息的回调
  void _updatePhoneData(String phoneNumber) {
    setState(() {
      _user.phoneNumber = phoneNumber;
    });
  }

  // 更新社交账号信息的回调
  void _updateSocialData(String socialAccount) {
    setState(() {
      _user.socialAccount = socialAccount;
    });
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: IntroductionScreen(
        controlsMargin: const EdgeInsets.fromLTRB(0, 99, 0, 0),
        curve: Curves.easeOutCubic,
        animationDuration: 450,
        freeze: true,
        showBackButton: true,
        showNextButton: true,
        showDoneButton: true,
        // 给每个子页面传递对应回调
        rawPages: [
          SignUpEmail(onUpdateData: _updateEmailData),
          SignUpNumbers(onUpdateData: _updatePhoneData),
          SignUpSocialNetwork(onUpdateData: _updateSocialData),
        ],
        back: Text(
          "返回",
          style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 18,
            color: Theme.of(context).primaryColor,
          ),
        ),
        next: Text(
          "下一步",
          style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 18,
            color: Theme.of(context).primaryColor,
          ),
        ),
        done: Text(
          "完成",
          style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 18,
            color: Theme.of(context).primaryColor,
          ),
        ),
        onDone: () {
          // 点击完成时直接使用父组件中已收集的所有数据
          print("保存用户数据:${_user.email}, ${_user.phoneNumber}, ${_user.socialAccount}");
          // 此处添加数据持久化逻辑,比如调用API存入数据库
        }
      ),
    );
  }
}

步骤2:修改SignUpEmail页面

让子页面接收回调函数,在表单验证通过后调用回调更新父组件数据:

class SignUpEmail extends StatefulWidget {
  // 定义回调函数类型
  final Function(String email, String password, String repeatPassword) onUpdateData;

  const SignUpEmail({Key? key, required this.onUpdateData}) : super(key: key);

  static const routeName = "/signUpEmail";

  @override
  State<SignUpEmail> createState() => _SignUpEmailState();
}

class _SignUpEmailState extends State<SignUpEmail> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _passwordWiederholenController = TextEditingController();

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    _passwordWiederholenController.dispose();
    super.dispose();
  }

  // 验证表单并同步数据到父组件
  void _syncDataToParent() {
    if (_formKey.currentState!.validate()) {
      widget.onUpdateData(
        _emailController.text.trim(),
        _passwordController.text,
        _passwordWiederholenController.text,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        reverse: true,
        child: Column(
          children: [
            Form(
              key: _formKey,
              child: Column(
                children: [
                  textfeld(
                    icon: Icons.mail,
                    hintText: "MaxMustermann@yahoo.de",
                    labelText: "邮箱地址",
                    keyboardType: TextInputType.emailAddress,
                    obscureText: false,
                    autofocus: false,
                    controller: _emailController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return "请输入有效的邮箱地址";
                      }
                      if (!value.contains(
                        RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"),
                      )) {
                        return "邮箱地址格式无效";
                      }
                      return null;
                    },
                    onChanged: (_) => _syncDataToParent(),
                  ),
                  textfeld(
                    icon: Icons.lock,
                    hintText: "密码至少8位",
                    labelText: "密码",
                    keyboardType: TextInputType.visiblePassword,
                    obscureText: true,
                    autofocus: false,
                    controller: _passwordController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return "请输入密码";
                      }
                      if (value.length <= 7) {
                        return "密码长度至少8位";
                      }
                      return null;
                    },
                    onChanged: (_) => _syncDataToParent(),
                  ),
                  textfeld(
                    icon: Icons.lock,
                    hintText: "重复密码至少8位",
                    labelText: "重复密码",
                    keyboardType: TextInputType.visiblePassword,
                    obscureText: true,
                    autofocus: false,
                    controller: _passwordWiederholenController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return "请重复输入密码";
                      }
                      if (value.length <= 7) {
                        return "密码长度至少8位";
                      }
                      if (value != _passwordController.text) {
                        return "两次输入的密码不一致";
                      }
                      return null;
                    },
                    onChanged: (_) => _syncDataToParent(),
                  ),
                ],
              ),
            ),
          ],
        ),
        padding: const EdgeInsets.only(bottom: 81),
      ),
    );
  }
}

步骤3:修改SignUpNumbers和SignUpSocialNetwork页面

参照SignUpEmail的模式,为这两个页面添加回调参数,在输入变化时调用回调更新父组件对应字段即可。


方案二:共享TextEditingController

父组件创建所有子页面需要的TextEditingController,传递给对应子页面,父组件可直接通过控制器获取输入内容,适合轻量场景。

修改SignUpOnbordingScreen

class _SignUpOnbordingScreenState extends State<SignUpOnbordingScreen> {
  // 父组件统一创建所有输入控制器
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _repeatPasswordController = TextEditingController();
  final _phoneController = TextEditingController();
  final _socialController = TextEditingController();

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    _repeatPasswordController.dispose();
    _phoneController.dispose();
    _socialController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: IntroductionScreen(
        // ...其他属性不变
        rawPages: [
          SignUpEmail(
            emailController: _emailController,
            passwordController: _passwordController,
            repeatPasswordController: _repeatPasswordController,
          ),
          SignUpNumbers(phoneController: _phoneController),
          SignUpSocialNetwork(socialController: _socialController),
        ],
        onDone: () {
          // 直接通过控制器收集所有数据
          final user = User(
            id: DateTime.now().toString(),
            email: _emailController.text.trim(),
            password: _passwordController.text,
            passwordWiederholen: _repeatPasswordController.text,
            phoneNumber: _phoneController.text,
            socialAccount: _socialController.text,
          );
          print("保存用户数据:${user.email}, ${user.phoneNumber}");
          // 添加数据持久化逻辑
        },
      ),
    );
  }
}

修改SignUpEmail页面

接收父组件传递的控制器,无需自行创建:

class SignUpEmail extends StatelessWidget {
  final TextEditingController emailController;
  final TextEditingController passwordController;
  final TextEditingController repeatPasswordController;

  const SignUpEmail({
    Key? key,
    required this.emailController,
    required this.passwordController,
    required this.repeatPasswordController,
  }) : super(key: key);

  static const routeName = "/signUpEmail";

  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        reverse: true,
        child: Column(
          children: [
            Form(
              key: _formKey,
              child: Column(
                children: [
                  textfeld(
                    icon: Icons.mail,
                    hintText: "MaxMustermann@yahoo.de",
                    labelText: "邮箱地址",
                    keyboardType: TextInputType.emailAddress,
                    obscureText: false,
                    autofocus: false,
                    controller: emailController,
                    validator: (value) {
                      if (value!.isEmpty) {
                        return "请输入有效的邮箱地址";
                      }
                      if (!value.contains(
                        RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"),
                      )) {
                        return "邮箱地址格式无效";
                      }
                      return null;
                    },
                  ),
                  // 其余输入框分别使用passwordController和repeatPasswordController,验证逻辑同前
                ],
              ),
            ),
          ],
        ),
        padding: const EdgeInsets.only(bottom: 81),
      ),
    );
  }
}

注意事项

  1. 确保User类包含所有需要的字段;
  2. 方案一更适合复杂表单,能统一管理数据状态;方案二更简单,适合轻量场景;
  3. 可给IntroductionScreen的onNext回调添加表单验证逻辑,确保当前页面数据有效后再进入下一页。

内容的提问来源于stack exchange,提问作者Parla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:01:18