9

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?

Kris
  • 3,091
  • 20
  • 28

5 Answers5

8

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());
Abdul Wahab
  • 411
  • 6
  • 15
  • 1
    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 focus – mister_cool_beans May 02 '22 at 17:09
  • @mister_cool_beans Add `FocusScope.of(context).requestFocus(new FocusNode())` for both `onTap()` and `onChanged()` – Amin Joharinia Jul 22 '23 at 13:35
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,
                );
            })),
    ],
)
keikai
  • 14,085
  • 9
  • 49
  • 68
Bobsar0
  • 261
  • 3
  • 6
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.

chunhunghan
  • 51,087
  • 5
  • 102
  • 120
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.

Pratham Sarankar
  • 555
  • 6
  • 10
0

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());
                         
                        },
                      ),
Amin Joharinia
  • 1,643
  • 2
  • 9
  • 9