TextField focus stuck when dropdown button is selected
Asked Answered
K

5

10

I have a text field and a drop-down menu, both controlled by a Bloc. The problem I have is that as soon as the text field gets selected, it won't give up the focus if the user then tries to select something from the dropdown menu. The menu appears and then disappears an instant later and the focus is still on the text field.

Here is a basic app that demonstrates the problem:

import 'dart:async';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Textfield Focus Example',
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {

  FormBloc formBloc = FormBloc();

  final List<DropdownMenuItem> userMenuItems = ['Bob', 'Frank']
      .map((String name) => DropdownMenuItem(
            value: name,
            child: Text(name),
          ))
      .toList();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            // user - drop down menu
            Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('To: '),
                StreamBuilder<String>(
                    stream: formBloc.selectedUser,
                    builder: (context, snapshot) {
                      return DropdownButton(
                          items: userMenuItems,
                          value: snapshot.data,
                          onChanged: formBloc.selectUser);
                    }),
              ],
            ),

            // amount - text field
            Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Amount: '),
                Container(
                    width: 100.0,
                    child: StreamBuilder<double>(
                        stream: formBloc.billAmount,
                        builder: (context, snapshot) {
                          return TextField(
                            keyboardType: TextInputType.number,
                            onChanged: formBloc.newBillAmount,
                          );
                        })),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class FormBloc {
  StreamController<String> _selectedUserController = StreamController<String>();
  Stream<String> get selectedUser =>
      _selectedUserController.stream;
  Function get selectUser => _selectedUserController.sink.add;

  //Amount
  StreamController<double> _billAmountController = StreamController<double>();
  Stream<double> get billAmount =>
      _billAmountController.stream;
  void newBillAmount(String amt) =>
      _billAmountController.sink.add(double.parse(amt));


  void dispose() {
    _selectedUserController.close();
    _billAmountController.close();
  }
}

Do I manually need to declare the FocusNode for the textField and tell it when to give up focus? Or is there some other reason that the text field is hogging all the attention?

Kalahari answered 22/10, 2019 at 23:35 Comment(0)
N
6

Add this line of code to your TextField: focusNode: FocusNode(canRequestFocus: false).

This should prevent your TextField from requesting focus after clicking on the dropdown.

Code:

// amount - text field
Row(
    mainAxisSize: MainAxisSize.min,
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
    Text('Amount: '),
    Container(
        width: 100.0,
        child: StreamBuilder<double>(
            stream: formBloc.billAmount,
            builder: (context, snapshot) {
                return TextField(
                focusNode: FocusNode(canRequestFocus: false)
                keyboardType: TextInputType.number,
                onChanged: formBloc.newBillAmount,
                );
            })),
    ],
)
Nilla answered 25/3, 2020 at 0:29 Comment(1)
Also you can try using autofocus: false in your TextField.Lamprophyre
L
9

Sorry for late answer you need to add following code in onTapListener of DropDownButton Widget.It will remove focus on text field when you select in drop down menu or click outside of screen.Thanks

FocusScope.of(context).requestFocus(new FocusNode());
Lox answered 17/5, 2020 at 0:8 Comment(2)
this solution does not work in scenarios where the user clicks elsewhere on screen which cause the dropdown menu to close, the dropdown item will stay in focusIntercalary
@Intercalary Add FocusScope.of(context).requestFocus(new FocusNode()) for both onTap() and onChanged()Silures
N
6

Add this line of code to your TextField: focusNode: FocusNode(canRequestFocus: false).

This should prevent your TextField from requesting focus after clicking on the dropdown.

Code:

// amount - text field
Row(
    mainAxisSize: MainAxisSize.min,
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
    Text('Amount: '),
    Container(
        width: 100.0,
        child: StreamBuilder<double>(
            stream: formBloc.billAmount,
            builder: (context, snapshot) {
                return TextField(
                focusNode: FocusNode(canRequestFocus: false)
                keyboardType: TextInputType.number,
                onChanged: formBloc.newBillAmount,
                );
            })),
    ],
)
Nilla answered 25/3, 2020 at 0:29 Comment(1)
Also you can try using autofocus: false in your TextField.Lamprophyre
S
1

add FocusScope.of(context).requestFocus(new FocusNode()) for both onTap() and onChanged()

                      DropdownButtonFormField(
                        value: 'Disable',
                        isExpanded: true,
                        decoration: InputDecoration(
                          enabledBorder: InputBorder.none,
                        ),
                        hint: Center(
                          child: Text("data"),
                        ),`
                        items: menuItems,
                        onTap: () {
                          FocusScope.of(context).requestFocus(new FocusNode());
                        },
                        onChanged: (value) {
                          FocusScope.of(context).requestFocus(new FocusNode());
                         
                        },
                      ),
Silures answered 22/7, 2023 at 13:33 Comment(0)
W
0

This issue has solved and merged to flutter master channel
https://github.com/flutter/flutter/pull/42482

This gets around the fact that we can't currently have a dropdown and a text field on the same page because the keyboard disappearing when the dropdown gets focus causes a metrics change, and the dropdown immediately disappears when activated.

Wilen answered 23/10, 2019 at 2:36 Comment(0)
S
0

The answer above is correct only in the case you don't want to call requestFocus() method. But in my case it was a chatting app and I wanted the textfield to get focused when the message is swiped. And if set the boolean parameter canRequestFocus, false. Then I am not able to do it.

In the chatPage appbar i was using a popupmenu which was causing the same problem (getting focused unintentionally.)

So, what worked for me is, in the top most of the method onSelected(String str) of popupmenu I called this statement :

messageFocusNode.nextFocus(); //messageFocusNode is the focusNode of the TextField.

Although I don't why and how, this worked for me. I am new to flutter, if you know the reason please update my answer.

Samos answered 15/4, 2021 at 11:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.