Home > Blockchain >  Not able to remove focus from input field
Not able to remove focus from input field

Time:11-23

I have four textfields, a title field, a details field, a date field, and a time field. Both the date and time fields are wrapped within a gesture detector, and onTap calls a pickDateAndTime method. The problem is that when I click on the date field and try to manually change the time through the input rather than the dial way, the focus goes to the title field and when I am still on the time picker and type something in the time picker, the title field gets changed with the new input. The weird part is that this error just appeared out of nowhere, and there are no errors reported in the console.

class TodoScreen extends StatefulWidget {
  final int? todoIndex;
  final int? arrayIndex;

  const TodoScreen({Key? key, this.todoIndex, this.arrayIndex})
      : super(key: key);

  @override
  State<TodoScreen> createState() => _TodoScreenState();
}

class _TodoScreenState extends State<TodoScreen> {
  final ArrayController arrayController = Get.find();
  final AuthController authController = Get.find();
  final String uid = Get.find<AuthController>().user!.uid;
  late TextEditingController _dateController;
  late TextEditingController _timeController;
  late TextEditingController titleEditingController;
  late TextEditingController detailEditingController;

  late String _setTime, _setDate;
  late String _hour, _minute, _time;
  late String dateTime;
  late bool done;

  @override
  void initState() {
    super.initState();
    String title = '';
    String detail = '';
    String date = '';
    String? time = '';

    if (widget.todoIndex != null) {
      title = arrayController
              .arrays[widget.arrayIndex!].todos![widget.todoIndex!].title ??
          '';
      detail = arrayController
              .arrays[widget.arrayIndex!].todos![widget.todoIndex!].details ??
          '';
      date = arrayController
          .arrays[widget.arrayIndex!].todos![widget.todoIndex!].date!;
      time = arrayController
          .arrays[widget.arrayIndex!].todos![widget.todoIndex!].time;
    }

    _dateController = TextEditingController(text: date);
    _timeController = TextEditingController(text: time);
    titleEditingController = TextEditingController(text: title);
    detailEditingController = TextEditingController(text: detail);
    done = (widget.todoIndex == null)
        ? false
        : arrayController
            .arrays[widget.arrayIndex!].todos![widget.todoIndex!].done!;
  }

  DateTime selectedDate = DateTime.now();
  TimeOfDay selectedTime = TimeOfDay(
      hour: (TimeOfDay.now().minute > 55)
          ? TimeOfDay.now().hour   1
          : TimeOfDay.now().hour,
      minute: (TimeOfDay.now().minute > 55) ? 0 : TimeOfDay.now().minute   5);

  Future<DateTime?> _selectDate() => showDatePicker(
      builder: (context, child) {
        return datePickerTheme(child);
      },
      initialEntryMode: DatePickerEntryMode.calendarOnly,
      context: context,
      initialDate: selectedDate,
      initialDatePickerMode: DatePickerMode.day,
      firstDate: DateTime.now(),
      lastDate: DateTime(DateTime.now().year   5));

  Future<TimeOfDay?> _selectTime() => showTimePicker(
      builder: (context, child) {
        return timePickerTheme(child);
      },
      context: context,
      initialTime: selectedTime,
      initialEntryMode: TimePickerEntryMode.input);

  Future _pickDateTime() async {
    DateTime? date = await _selectDate();
    if (date == null) return;
    if (date != null) {
      selectedDate = date;
      _dateController.text = DateFormat("MM/dd/yyyy").format(selectedDate);
    }
    TimeOfDay? time = await _selectTime();
    if (time == null) {
      _timeController.text = formatDate(
          DateTime(
              DateTime.now().year,
              DateTime.now().day,
              DateTime.now().month,
              DateTime.now().hour,
              DateTime.now().minute   5),
          [hh, ':', nn, " ", am]).toString();
    }
    if (time != null) {
      selectedTime = time;
      _hour = selectedTime.hour.toString();
      _minute = selectedTime.minute.toString();
      _time = '$_hour : $_minute';
      _timeController.text = _time;
      _timeController.text = formatDate(
          DateTime(2019, 08, 1, selectedTime.hour, selectedTime.minute),
          [hh, ':', nn, " ", am]).toString();
    }
  }

  @override
  Widget build(BuildContext context) {
    bool visible =
        (_dateController.text.isEmpty && _timeController.text.isEmpty)
            ? false
            : true;

    final formKey = GlobalKey<FormState>();

    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        title: Text((widget.todoIndex == null) ? 'New Task' : 'Edit Task',
            style: menuTextStyle),
        leadingWidth: (MediaQuery.of(context).size.width < 768) ? 90.0 : 100.0,
        leading: Center(
          child: Padding(
            padding: (MediaQuery.of(context).size.width < 768)
                ? const EdgeInsets.only(left: 0)
                : const EdgeInsets.only(left: 21.0),
            child: TextButton(
              style: const ButtonStyle(
                splashFactory: NoSplash.splashFactory,
              ),
              onPressed: () {
                Get.back();
              },
              child: Text(
                "Cancel",
                style: paragraphPrimary,
              ),
            ),
          ),
        ),
        centerTitle: true,
        actions: [
          Center(
            child: Padding(
              padding: (MediaQuery.of(context).size.width < 768)
                  ? const EdgeInsets.only(left: 0)
                  : const EdgeInsets.only(right: 21.0),
              child: TextButton(
                style: const ButtonStyle(
                  splashFactory: NoSplash.splashFactory,
                ),
                onPressed: () async {
                },
                child: Text((widget.todoIndex == null) ? 'Add' : 'Update',
                    style: paragraphPrimary),
              ),
            ),
          )
        ],
      ),
      body: SafeArea(
        child: Container(
          width: double.infinity,
          padding: (MediaQuery.of(context).size.width < 768)
              ? const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0)
              : const EdgeInsets.symmetric(horizontal: 35.0, vertical: 15.0),
          child: Column(
            children: [
              Form(
                key: formKey,
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    TextFormField(
                        validator: Validator.titleValidator,
                        controller: titleEditingController,
                        autofocus: true, // problem here
                        autocorrect: false,
                        cursorColor: Colors.grey,
                        maxLines: 1,
                        maxLength: 25,
                        textInputAction: TextInputAction.next,
                        decoration: InputDecoration(
                            counterStyle: counterTextStyle,
                            hintStyle: hintTextStyle,
                            hintText: "Title",
                            border: InputBorder.none),
                        style: todoScreenStyle),
                    primaryDivider,
                    TextField(
                        controller: detailEditingController,
                        maxLines: null,
                        autocorrect: false,
                        cursorColor: Colors.grey,
                        textInputAction: TextInputAction.done,
                        decoration: InputDecoration(
                            counterStyle: counterTextStyle,
                            hintStyle: hintTextStyle,
                            hintText: "Notes",
                            border: InputBorder.none),
                        style: todoScreenDetailsStyle),
                  ],
                ),
              ),
              Visibility(
                visible: (widget.todoIndex != null) ? true : false,
                child: GestureDetector(
                  onTap: () {},
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        "Completed",
                        style: todoScreenStyle,
                      ),
                      Transform.scale(
                        scale: 1.3,
                        child: Theme(
                            data: ThemeData(
                                unselectedWidgetColor: const Color.fromARGB(
                                    255, 187, 187, 187)),
                            child: Checkbox(
                                shape: const CircleBorder(),
                                checkColor: Colors.white,
                                activeColor: primaryColor,
                                value: done,
                                side: Theme.of(context).checkboxTheme.side,
                                onChanged: (value) {
                                  setState(() {
                                    done = value!;
                                  });
                                })),
                      )
                    ],
                  ),
                ),
              ),
              GestureDetector(
                onTap: () async {
                  await _pickDateTime();
                  setState(() {
                    visible = true;
                  });
                },
                child: Column(
                  children: [
                    Row(
                      children: [
                        Flexible(
                          child: TextField(
                            enabled: false,
                            controller: _dateController,
                            onChanged: (String val) {
                              _setDate = val;
                            },
                            decoration: InputDecoration(
                                hintText: "Date",
                                hintStyle: hintTextStyle,
                                border: InputBorder.none),
                            style: todoScreenStyle,
                          ),
                        ),
                        visible
                            ? IconButton(
                                onPressed: () {
                                  _dateController.clear();
                                  _timeController.clear();
                                  setState(() {});
                                },
                                icon: const Icon(
                                  Icons.close,
                                  color: Colors.white,
                                ))
                            : Container()
                      ],
                    ),
                    primaryDivider,
                    TextField(
                      onChanged: (String val) {
                        _setTime = val;
                      },
                      enabled: false,
                      controller: _timeController,
                      decoration: InputDecoration(
                          hintText: "Time",
                          hintStyle: hintTextStyle,
                          border: InputBorder.none),
                      style: todoScreenStyle,
                    )
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

CodePudding user response:

Add a focusNode in your textField:

FocusNode focusNode = FocusNode();

TextField(
    focusNode: focusNode,
);

And then in the gesture detector, add that following code to unselect the textfield input:

FocusScope.of(context).requestFocus(FocusNode());

CodePudding user response:

simply wrap your Scaffold widget GestureDetector and add FocusScope.of(context).requestFocus(FocusNode()); it will automatically unfocused text field when you click anywhere on your screen

GestureDetector(
        onTap: () {
          FocusScope.of(context).requestFocus(FocusNode());
        },
     child: Scaffold()
)

CodePudding user response:

You can use below code to remove focus in gesture detector event

 FocusScopeNode currentFocus = FocusScope.of(context);
    if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
      currentFocus.unfocus();
    }
  • Related