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

Flutter pop返回上一页时表单输入数据自动重置问题解决方案

问题根因
  • State类定义存在语法错误:DataInfoPage的createState返回类型与实际State类不匹配,路由切换时会触发页面异常重建,重置本地状态。
  • 表单数据(输入框内容、选中日期范围)全部存储在页面State的本地变量中,未托管到已接入的AddTripBloc,页面一旦重建就会恢复初始空值。
  • 自定义表单组件customfields为StatelessWidget,却在内部维护了可变的_validate校验状态,每次页面重建都会重置该值,干扰表单状态。
修复步骤

1. 修正State类定义错误

删除类内无效的createState声明,修正State匹配关系:

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

  @override
  State<DataInfoPage> createState() => _DataInfoPageState();
}

class _DataInfoPageState extends State<DataInfoPage> {
  // 删除原有错误代码行:_DataInfoPageState createState() => _DataInfoPageState();
  String date = "";

  final FirebaseAuth _auth = FirebaseAuth.instance;
  User? user;
  var name = '';
  // 其余原有变量保留

2. 将表单状态托管到AddTripBloc

将所有表单数据从页面本地变量迁移到Bloc存储,从根源避免页面重建导致的数据丢失:

  1. 先在AddTripState中新增表单字段,实现copyWith方法支持状态更新:
class AddTripState {
  final String tripName;
  final DateTimeRange? selectedDateRange;
  final List<String> uploadedImagePaths;
  // 保留原有其他状态字段

  const AddTripState({
    this.tripName = "",
    this.selectedDateRange,
    this.uploadedImagePaths = const [],
    // 保留原有其他字段初始化
  });

  AddTripState copyWith({
    String? tripName,
    DateTimeRange? selectedDateRange,
    List<String>? uploadedImagePaths,
    // 保留原有其他参数
  }) {
    return AddTripState(
      tripName: tripName ?? this.tripName,
      selectedDateRange: selectedDateRange ?? this.selectedDateRange,
      uploadedImagePaths: uploadedImagePaths ?? this.uploadedImagePaths,
      // 保留原有其他字段赋值
    );
  }
}
  1. 新增对应状态更新事件:
class UpdateTripNameEvent extends AddTripEvent {
  final String tripName;
  UpdateTripNameEvent(this.tripName);
}

class UpdateDateRangeEvent extends AddTripEvent {
  final DateTimeRange dateRange;
  UpdateDateRangeEvent(this.dateRange);
}

class UpdateUploadedImagesEvent extends AddTripEvent {
  final List<String> imagePaths;
  UpdateUploadedImagesEvent(this.imagePaths);
}
  1. 在Bloc的事件回调中处理状态更新:
on<UpdateTripNameEvent>((event, emit) {
  emit(state.copyWith(tripName: event.tripName));
});
on<UpdateDateRangeEvent>((event, emit) {
  emit(state.copyWith(selectedDateRange: event.dateRange));
});
on<UpdateUploadedImagesEvent>((event, emit) {
  emit(state.copyWith(uploadedImagePaths: event.imagePaths));
});
  1. 页面初始化时从Bloc读取已存数据填充表单,监听输入变化同步状态到Bloc:
@override
void initState() {
  super.initState();
  initUser();
  // 读取Bloc已存数据初始化
  final formState = context.read<AddTripBloc>().state;
  tripname.text = formState.tripName;
  _selectedDateRange = formState.selectedDateRange;
  // 监听输入同步
  tripname.addListener(() {
    context.read<AddTripBloc>().add(UpdateTripNameEvent(tripname.text));
  });
}
  1. 日期选择完成后同步状态到Bloc:
void _show() async {
  final DateTimeRange? result = await showDateRangePicker(
    context: context,
    firstDate: DateTime(2022, 1, 1),
    lastDate: DateTime(2030, 12, 31),
    currentDate: DateTime.now(),
    saveText: 'Done.',
  );

  if (result != null) {
    setState(() {
      _selectedDateRange = result;
    });
    context.read<AddTripBloc>().add(UpdateDateRangeEvent(result));
  }
}
  1. 给Form组件添加PageStorageKey,进一步缓存页面滚动和表单状态:
Form(
  key: _formKey,
  key: const PageStorageKey('data_info_form'),
  child: Column(
    // 原有子组件不变
  )
)

3. 修复自定义表单组件问题

删除customfields内部维护的无效_validate变量,校验逻辑完全交给Form的validator机制处理,避免重建重置状态:

class customfields extends StatelessWidget {
  customfields(
      {required this.hintValue,
      this.labeltxt = "",
      required this.keyboardtype,
      this.maxvalue = 1,
      required this.text});
  final String hintValue;
  final String labeltxt;
  final int maxvalue;
  final TextInputType keyboardtype;
  final TextEditingController text;
  // 删除原有 bool _validate = false; 声明

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: <Widget>[
          TextFormField(
            controller: text,
            cursorColor: Colors.black,
            style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
            textAlignVertical: TextAlignVertical.center,
            inputFormatters: <TextInputFormatter>[
              FilteringTextInputFormatter.allow(
                  RegExp('[a-z A-Z 0-9 #?!@%^&* ? @ ^_ . : ! | "" \'-]')),
            ],
            decoration: InputDecoration(
              border: const UnderlineInputBorder(),
              hintText: hintValue,
              labelText: labeltxt,
            ),
            keyboardType: keyboardtype,
            validator: (value) {
              if (value?.isEmpty ?? true) {
                return "Value Can't be empty.";
              }
              return null;
            },
          ),
        ],
      ),
    );
  }
}

4. 优化页面跳转传参逻辑

从相机页返回时直接传回选中的图片列表,同步到Bloc,不要重新初始化表单页:

// DataInfoPage中跳转相机页的逻辑
ElevatedButton(
  onPressed: () async {
    final imageResult = await Navigator.of(context).push<List<String>>(MaterialPageRoute(
        builder: (context) => CameraWidget()));
    if (imageResult != null) {
      context.read<AddTripBloc>().add(UpdateUploadedImagesEvent(imageResult));
    }
  },
  child: const Text("Upload Images of Trip *"),
),

在CameraWidget点击完成按钮返回时,将选中的图片路径列表作为参数传入pop:

// CameraWidget中完成按钮逻辑
Navigator.pop(context, selectedImagePathList);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 23:27:36