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

Flutter中UpdatingTaskPage无法显示widget传递的现有数据求助

Flutter 更新页面无法显示Firestore传递的现有数据问题

问题描述

Flutter新手,从HomePage点击列表项跳转至UpdatingTaskPage时,color、date、startTime、endTime、remind、repeat字段仅显示默认值,而非通过widget传递的Firestore现有数据(例如Firestore中remind为15分钟,但页面显示默认的5分钟)。

相关截图

  • HomePage界面:
    HomePage
  • Firebase数据(remind值应为15分钟却显示默认5分钟,repeat为Daily而非None):
    Firebase Data
  • UpdatingTaskPage显示默认值而非现有数据:
    UpdatingTaskPage显示问题

UpdatingTaskPage代码

class UpdatingTaskPage extends StatefulWidget {
  final String id, title, note, date, startTime, endTime, repeat;
  final int color, remind;
  final bool isCompleted;

  const UpdatingTaskPage(
      {super.key,
      required this.id,
      required this.title,
      required this.note,
      required this.date,
      required this.startTime,
      required this.endTime,
      required this.repeat,
      required this.color,
      required this.remind,
      required this.isCompleted});

  @override
  State<UpdatingTaskPage> createState() => _UpdatingTaskPageState();
}

class _UpdatingTaskPageState extends State<UpdatingTaskPage> {
  static TaskController controller = Get.put(TaskController());
  final task = controller.tasks.length;

  TextEditingController titleController = TextEditingController();
  TextEditingController noteController = TextEditingController();

  late DateTime _selecteDate = DateTime.now();
  late String _startTime =
      DateFormat('hh:mm a').format(DateTime.now()).toString();
  String _endTime = DateFormat('hh:mm a')
      .format(DateTime.now().add(const Duration(minutes: 60)))
      .toString();
  int _selectedRemind = 5;
  List<int> remindList = [5, 10, 15, 20];
  String _selectedRepeat = 'None';
  List<String> repeatList = ['None', 'Daily', 'Weekly', 'Monthly'];
  int _selectedColor = 0;
  List<Color> colorList = [
    bluishClr,
    yellowClr,
    redClr,
    greenClr,
  ];

  @override
  Widget build(BuildContext context) {
    titleController.text = widget.title;
    noteController.text = widget.note;
    return Scaffold(
      appBar: AppBar(
        title: const Text("Update task!"),
        centerTitle: true,
        actions: [
          IconButton(
              onPressed: () {
                // this icon button is for the user to signout
                AuthController.instance.logout();
              },
              icon: const Icon(Icons.logout_rounded))
        ],
      ),
      body: Container(
        padding: const EdgeInsets.symmetric(horizontal: 20.0),
        child: SingleChildScrollView(
          child: Column(
            children: [
              //Title
              InputField(
                title: 'Title',
                hint: 'Enter your title here...',
                controller: titleController,
              ),
              //Note
              InputField(
                title: 'Note',
                hint: 'Enter your note here...',
                controller: noteController,
              ),
              //Date
              InputField(
                title: 'Date',
                hint: DateFormat.yMd().format(_selecteDate),
                child: IconButton(
                  onPressed: () => _getDateFromUser(),
                  icon: const Icon(
                    Icons.calendar_today_outlined,
                    color: Colors.grey,
                  ),
                ),
              ),
              //Date Range
              Row(
                children: [
                  Expanded(
                    child: InputField(
                      title: 'Start Time',
                      hint: _startTime,
                      child: IconButton(
                        onPressed: () => _getTimeFromUser(isStartTime: true),
                        icon: const Icon(
                          Icons.access_time_rounded,
                          color: Colors.grey,
                        ),
                      ),
                    ),
                  ),
                  Expanded(
                    child: InputField(
                      title: 'End Time',
                      hint: _endTime,
                      child: IconButton(
                        onPressed: () => _getTimeFromUser(isStartTime: false),
                        icon: const Icon(
                          Icons.access_time_rounded,
                          color: Colors.grey,
                        ),
                      ),
                    ),
                  ),
                ],
              ),
              //Remind
              InputField(
                title: 'Alert',
                hint: '$_selectedRemind minutes early',
                child: DropdownButton(
                  onChanged: (String? newVal) {
                    setState(() {
                      _selectedRemind = int.parse(newVal!);
                    });
                  },
                  items: remindList
                      .map<DropdownMenuItem<String>>(
                        (e) => DropdownMenuItem<String>(
                          value: e.toString(),
                          child: Text('$e minutes'),
                        ),
                      )
                      .toList(),
                  icon: const Icon(
                    Icons.keyboard_arrow_down,
                    size: 32,
                    color: Colors.grey,
                  ),
                  elevation: 3,
                  underline: Container(height: 0),
                  borderRadius: BorderRadius.circular(15),
                ),
              ),
              //Repeat
              InputField(
                title: 'Repeat',
                hint: _selectedRepeat,
                child: DropdownButton<String>(
                  onChanged: (String? value) {
                    setState(() {
                      _selectedRepeat = value!;
                    });
                  },
                  value: widget.repeat,
                  items: repeatList
                      .map<DropdownMenuItem<String>>(
                        (e) => DropdownMenuItem<String>(
                          value: e,
                          child: Text(e),
                        ),
                      )
                      .toList(),
                  icon: const Icon(
                    Icons.keyboard_arrow_down,
                    size: 32,
                    color: Colors.grey,
                  ),
                  elevation: 3,
                  underline: Container(height: 0),
                  borderRadius: BorderRadius.circular(15),
                ),
              ),
              //Color
              Container(
                margin: const EdgeInsets.symmetric(
                    vertical: 10.0, horizontal: 10.0),
                alignment: Alignment.centerLeft,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('Color'),
                    Row(
                      children: List.generate(
                        colorList.length,
                        (index) => Padding(
                          padding: const EdgeInsets.only(right: 5.0, top: 8),
                          child: InkWell(
                            onTap: () {
                              setState(() {
                                // Value(widget.color);
                                _selectedColor = index;
                              });
                            },
                            borderRadius: BorderRadius.circular(50),
                            child: CircleAvatar(
                              backgroundColor: colorList[index],
                              child: widget.color == index
                                  ? null
                                  : index == _selectedColor
                                      ? const Icon(
                                          Icons.check,
                                          color: Colors.white,
                                        )
                                      : null,
                              // child: index == _selectedColor
                              //     ? const Icon(
                              //         Icons.check,
                              //         color: Colors.white,
                              //       )
                              //     : null,
                            ),
                          ),
                        ),
                      ),
                    )
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
      floatingActionButton: MyButton(
          label: 'Save',
          onTap: () {
            _validateData();
          }),
    );
  }

  _validateData() async {
    if (titleController.text.isNotEmpty && noteController.text.isNotEmpty) {
      print(1);
      _updateTaskToDb();
      Get.back();
    } else if (titleController.text.isEmpty || noteController.text.isEmpty) {
      print(2);

      Get.snackbar(
        'Required',
        'All fileds are required',
        backgroundColor: Colors.white,
        snackPosition: SnackPosition.BOTTOM,
        colorText: Colors.black,
        icon: const Icon(
          Icons.warning_amber_rounded,
          color: Colors.red,
        ),
      );
    } else {
      print('######## Error Here ! ########');
    }
  }

  _updateTaskToDb() async {
    await FirestoreDB.updateTask(
      taskModel: Task(
        id: FirebaseAuth.instance.currentUser!.uid,
        title: titleController.text,
        note: noteController.text,
        isCompleted: false,
        date: DateFormat.yMd().format(_selecteDate),
        startTime: _startTime,
        endTime: _endTime,
        color: _selectedColor,
        remind: _selectedRemind,
        repeat: _selectedRepeat,
      ),
      documentId: widget.id,
    );
    Get.snackbar(
      'Updating',
      'Successfully update',
      backgroundColor: whiteClr,
      colorText: Colors.black,
    );
  }

  _getDateFromUser() async {
    DateTime? _pickedDate = await showDatePicker(
      context: context,
      initialDate: _selecteDate,
      firstDate: DateTime(2020),
      lastDate: DateTime(2030),
    );
    if (_pickedDate != null) {
      setState(() {
        Value(widget.date);
        _selecteDate = _pickedDate;
      });
    } else {
      print('picked date empty !');
    }
  }

  _getTimeFromUser({required bool isStartTime}) async {
    TimeOfDay? _pickedTime = await showTimePicker(
      context: context,
      initialTime: TimeOfDay.now(),
    );
    if (_pickedTime != null) {
      setState(() {
        if (isStartTime) {
          _startTime = _pickedTime.format(context);
          print(_startTime);
        } else {
          _endTime = _pickedTime.format(context);
          print(_endTime);
        }
      });
    }
  }
}

问题原因及解决方法

核心问题是未在页面初始化阶段将widget传递的Firestore数据赋值给对应状态变量,且部分控件绑定逻辑错误,修复步骤如下:

1. 在initState中初始化状态变量

initState是StatefulWidget初始化时仅执行一次的方法,适合用来将widget传递的数据赋值给状态变量,替换默认值:

@override
void initState() {
  super.initState();
  // 初始化文本控制器
  titleController.text = widget.title;
  noteController.text = widget.note;
  
  // 将widget中的日期字符串转为DateTime对象
  _selecteDate = DateFormat.yMd().parse(widget.date);
  
  // 初始化时间
  _startTime = widget.startTime;
  _endTime = widget.endTime;
  
  // 初始化提醒时间
  _selectedRemind = widget.remind;
  
  // 初始化重复选项
  _selectedRepeat = widget.repeat;
  
  // 初始化颜色索引
  _selectedColor = widget.color;
}

2. 移除build方法中的控制器赋值

当前在build方法中设置titleController.text = widget.title,build会在每次setState时重新执行,会覆盖用户输入内容,必须将这两行移到initState中。

3. 修复Remind下拉框的value绑定

Remind的DropdownButton未设置value属性,无法显示选中的widget传递值,添加绑定:

DropdownButton(
  value: widget.remind.toString(), // 绑定widget传递的remind值
  onChanged: (String? newVal) {
    setState(() {
      _selectedRemind = int.parse(newVal!);
    });
  },
  // 其他代码不变
)

4. 修复颜色选择器的选中状态逻辑

当前颜色选择器的选中判断逻辑混乱,直接判断索引是否等于_selectedColor即可(已在initState中赋值为widget.color):

CircleAvatar(
  backgroundColor: colorList[index],
  child: index == _selectedColor
      ? const Icon(
          Icons.check,
          color: Colors.white,
        )
      : null,
)

5. 修复时间选择器的初始值

当前时间选择器初始值为TimeOfDay.now(),应改为从widget传递的时间字符串解析而来:

_getTimeFromUser({required bool isStartTime}) async {
  // 解析现有时间字符串为TimeOfDay
  TimeOfDay initialTime = TimeOfDay.fromDateTime(
    DateFormat('hh:mm a').parse(isStartTime ? _startTime : _endTime)
  );
  
  TimeOfDay? _pickedTime = await showTimePicker(
    context: context,
    initialTime: initialTime, // 使用解析后的初始时间
  );
  if (_pickedTime != null) {
    setState(() {
      if (isStartTime) {
        _startTime = _pickedTime.format(context);
      } else {
        _endTime = _pickedTime.format(context);
      }
    });
  }
}

6. 清理无用代码

删除_getDateFromUser方法中无用的Value(widget.date);代码,该行无实际作用。

完成以上修改后,UpdatingTaskPage即可正确显示Firestore传递的现有数据。


内容的提问来源于stack exchange,提问作者I Can Done

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 04:18:03