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

Flutter中如何从有状态组件PhoneFormField向无状态登录页传值

如何在LoginScreen中获取PhoneFormField内的手机号值

场景说明

我有一个无状态的登录页面LoginScreen,其中包含自定义有状态组件PhoneFormField。LoginScreen中的_buildPhoneNumberSubmittedBloc函数需要传入手机号参数,但该参数仅存在于PhoneFormField组件内部。

LoginScreen核心代码

Scaffold(
  resizeToAvoidBottomInset: true,
  backgroundColor: Colors.white,
  body: Form(
    key: _phoneFormKey,
    child: Container(
      margin: EdgeInsets.only(
          left: width * 0.08, right: width * 0.08, top: height * 0.1),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildIntroTexts(context),
          SizedBox(height: height * 0.125),
          PhoneFormField(),
          SizedBox(height: height * 0.07),
          _buildnextButton(context),
          //_buildPhoneNumberSubmittedBloc(phoneNumber!),
        ],
      ),
    ),
  ),
);

PhoneFormField核心代码

Row(
  children: [
    Expanded(
      flex: 1,
      child: Container(
        padding: EdgeInsets.symmetric(vertical: height * 0.015),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(6),
          border: Border.all(color: MyColors.lightGrey),
        ),
        child: GestureDetector(
          onTap: () async {
            final code = await countryPicker.showPicker(context: context);
            setState(() {
              countryCode = code;
            });
          },
          child: Row(
            children: [
              Container(
                margin: const EdgeInsets.only(left: 8.0),
                child: countryCode != null
                    ? Text(
                        generateCountryFlag(countryCode!.code),
                        style: TextStyle(fontSize: 18.sp),
                      )
                    : Text(
                        generateCountryFlag('eg'),
                        style: TextStyle(fontSize: 18.sp),
                      ),
              ),
              Container(
                padding: const EdgeInsets.symmetric(vertical: 4.0),
                margin: const EdgeInsets.symmetric(horizontal: 8.0),
                child: countryCode != null
                    ? Text(countryCode!.dialCode,
                        style: TextStyle(color: Colors.black, fontSize: 16.sp))
                    : Text('+20',
                        style: TextStyle(color: Colors.black, fontSize: 16.sp)),
              ),
            ],
          ),
        ),
      ),
    ),
    const SizedBox(width: 16),
    Expanded(
      flex: 2,
      child: Container(
          width: double.infinity,
          padding: EdgeInsets.symmetric(horizontal: width * 0.05),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(6),
            border: Border.all(color: MyColors.blue),
          ),
          child: TextFormField(
            autofocus: true,
            keyboardType: TextInputType.phone,
            textInputAction: TextInputAction.done,
            style: TextStyle(
              fontSize: 16.sp,
              color: Colors.black,
              letterSpacing: 1.5,
            ),
            decoration: InputDecoration(
              hintText: 'Phone Number',
              hintStyle: TextStyle(
                color: Colors.grey,
                fontSize: 16.sp,
                letterSpacing: 1,
              ),
              border: InputBorder.none,
            ),
            cursorColor: Colors.black,
            validator: (value) {
              if (value!.isEmpty) {
                return 'Please enter your phone number';
              } else if (value.length < 11) {
                return 'Please enter a valid phone number';
              }
              return null;
            },
            onSaved: (newValue) {
              phoneNumber = newValue;
            },
            onChanged: (value) {
              phoneNumber = value;
            },
          )),
    )
  ],
);

解决方案

方法1:通过回调函数实时传递值

这是父子组件通信最直接的方式,给PhoneFormField添加回调参数,在手机号变化时主动把值传给LoginScreen。

  1. 修改PhoneFormField的StatefulWidget定义,添加回调参数:
class PhoneFormField extends StatefulWidget {
  final void Function(String?) onPhoneChanged;

  const PhoneFormField({super.key, required this.onPhoneChanged});

  @override
  State<PhoneFormField> createState() => _PhoneFormFieldState();
}
  1. 在PhoneFormField的State中,触发回调更新父组件的值:
// 修改TextFormField的onChanged和onSaved
onChanged: (value) {
  phoneNumber = value;
  widget.onPhoneChanged(value); // 传递最新值给父组件
},
onSaved: (newValue) {
  phoneNumber = newValue;
  widget.onPhoneChanged(newValue); // 保存时同步传递
},
  1. 在LoginScreen中接收并维护手机号变量:
// LoginScreen中定义变量
String? _phoneNumber;

// 使用PhoneFormField时传入回调
PhoneFormField(
  onPhoneChanged: (value) {
    setState(() {
      _phoneNumber = value;
    });
  },
),

// 调用函数时传入值
_buildPhoneNumberSubmittedBloc(_phoneNumber!),

方法2:利用Form的GlobalKey统一获取表单值

因为LoginScreen已经使用了Form组件,可以通过Form的save方法统一触发子表单字段的保存逻辑,再获取值。

  1. 给PhoneFormField添加保存回调:
class PhoneFormField extends StatefulWidget {
  final void Function(String?) onPhoneSaved;

  const PhoneFormField({super.key, required this.onPhoneSaved});

  @override
  State<PhoneFormField> createState() => _PhoneFormFieldState();
}
  1. 在PhoneFormField的TextFormField的onSaved中触发回调:
onSaved: (newValue) {
  phoneNumber = newValue;
  widget.onPhoneSaved(newValue);
},
  1. 在LoginScreen的下一步按钮点击事件中,先验证并保存表单:
void _handleNext() {
  if (_phoneFormKey.currentState!.validate()) {
    _phoneFormKey.currentState!.save();
    // 此时_phoneNumber已更新,可调用目标函数
    _buildPhoneNumberSubmittedBloc(_phoneNumber!);
  }
}

// 使用PhoneFormField
PhoneFormField(
  onPhoneSaved: (value) {
    _phoneNumber = value;
  },
),

// _buildnextButton绑定点击事件
Widget _buildnextButton(BuildContext context) {
  return ElevatedButton(
    onPressed: _handleNext,
    child: const Text('Next'),
  );
}

方法3:状态管理工具(复杂场景可选)

如果项目中已经使用Provider、Riverpod等状态管理库,可以把手机号状态放到全局状态容器中,PhoneFormField负责更新状态,LoginScreen直接读取状态值即可。这种方式适合跨多层组件的状态共享。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:12:37