skip to Main Content

I’m working on a Flutter application where I need to focus and allow to write on a TextField when a button is clicked, but without showing the keyboard. I have a barcode scanner that inputs text into the focused field automatically, so I need the cursor to be in the TextField, but I don’t want the on-screen keyboard to appear.

Here’s my version

name: jtekt_mobile
description: "A new Flutter project."
publish_to: "none"
version: 0.1.0

environment:
  sdk: ">=3.3.3 <4.0.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0

flutter:
  uses-material-design: true

Here’s my code

import 'package:flutter/material.dart';
import 'package:jtekt_mobile/models/mean_model.dart';

class Mean extends StatefulWidget {
  const Mean({super.key});

  @override
  State<Mean> createState() => _MeanState();
}

class _MeanState extends State<Mean> {
  bool isInOutSelected = false;
  bool isNameSelected = false;
  bool exitSelected = false;
  bool entrySelected = false;

  Color redColor = Colors.red;
  Color greenColor = Colors.green;
  Color greyColor = Colors.grey;

  List<MeanModel> meanList = [];

  final FocusNode nameFocusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          flex: 1,
          child: Container(
            color: Colors.white,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                ElevatedButton(
                  onPressed: entryButton,
                  style: ElevatedButton.styleFrom(
                    backgroundColor: !isInOutSelected || entrySelected
                        ? greenColor
                        : greyColor,
                  ),
                  child: const Text(
                    "Entrée",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
                ElevatedButton(
                  onPressed: exitButton,
                  style: ElevatedButton.styleFrom(
                    backgroundColor:
                        !isInOutSelected || exitSelected ? redColor : greyColor,
                  ),
                  child: const Text(
                    "Sortie",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ],
            ),
          ),
        ),
        if (isInOutSelected)
          Expanded(
            flex: 5,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                Padding(
                  padding: const EdgeInsets.all(10),
                  child: TextField(
                    focusNode: nameFocusNode,
                    decoration: InputDecoration(
                      focusedBorder: OutlineInputBorder(
                        borderSide: BorderSide(
                            color: entrySelected ? greenColor : redColor,
                            width: 4),
                      ),
                      border: const OutlineInputBorder(),
                      labelText: ("Nom"),
                      enabledBorder: OutlineInputBorder(
                        borderSide: BorderSide(
                            color: entrySelected ? greenColor : redColor,
                            width: 2),
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 20),
                if (isNameSelected)
                  const Padding(
                    padding: EdgeInsets.all(10),
                    child: TextField(
                      decoration: InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: ("Moyen"),
                        enabledBorder: OutlineInputBorder(
                          borderSide: BorderSide(color: Colors.black, width: 2),
                        ),
                      ),
                    ),
                  ),
                const SizedBox(height: 20),
                Expanded(
                  child: SingleChildScrollView(
                    scrollDirection: Axis.vertical,
                    child: Column(
                      children: meanList
                          .map((mean) => ListTile(
                                title: Text(mean.username),
                                subtitle: Text(mean.meanNumber),
                                trailing: const Icon(Icons.delete),
                              ))
                          .toList(),
                    ),
                  ),
                ),
                if (isNameSelected)
                  Center(
                    child: ElevatedButton(
                      onPressed: validation,
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.blue,
                      ),
                      child: const Text(
                        "Valider",
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ),
                const SizedBox(height: 20),
              ],
            ),
          ),
      ],
    );
  }

  void entryButton() {
    setState(() {
      isInOutSelected = true;
      entrySelected = true;
      exitSelected = false;
    });
    nameFocusNode.requestFocus();
  }

  void exitButton() {
    setState(() {
      isInOutSelected = true;
      exitSelected = true;
      entrySelected = false;
    });
    nameFocusNode.requestFocus();
  }

  void validation() {}
}

What I want is when I click on the "Entrée" or "Sortie" button, it should set the focus on the "Nom" TextField and show the cursor, but without displaying the keyboard. I need to be able to input text into the TextField using a barcode scanner which automatically inputs text into the focused field.

I’ve tried various methods like SystemChannels.textInput.invokeMethod(‘TextInput.hide’), FocusNode().unfocus(), FocusManager.instance.primaryFocus?.unfocus(), FocusScope.of(context).unfocus(), and even using the input_with_keyboard_control (https://pub.dev/packages/input_with_keyboard_control/versions) library, but none of them worked (maybe for that i dont know how to use it)
I’ve seen this video very simple but it doesn’t work when i do the same in my code : https://www.youtube.com/watch?v=MKrEJtheGPk&t=59s

I’ve spent hours searching for a solution but haven’t found anything that works. How can I achieve this behavior in Flutter? Any help would be greatly appreciated.

2

Answers


  1. There is actually a much simpler way to do this. Create a TextEditingController and assign it to your TextField. Then when you scan the bar code, use the controller to update the text.

    You don’t actually need to focus the TextField to edit what’s inside of it. You can also prevent the keyboard from showing when the field is focused by setting readOnly to true:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MainApp());
    }
    
    class MainApp extends StatelessWidget {
      const MainApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: FormDemo(),
          ),
        );
      }
    }
    
    class FormDemo extends StatefulWidget {
      @override
      State<FormDemo> createState() => _FormDemoState();
    }
    
    class _FormDemoState extends State<FormDemo> {
      final TextEditingController controller = TextEditingController();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Column(
              children: [
                TextField(
                  controller: controller,
                  readOnly: true,
                  decoration: const InputDecoration(labelText: 'Field 1'),
                ),
                ElevatedButton(
                    onPressed: () {
                      controller.text = 'Hello World';
                    },
                    child: const Text('Add text'))
              ],
            ),
          ),
        );
      }
    }
    
    Login or Signup to reply.
  2. You can prevent the keyboard from appearing by setting readOnly : true in TextField .

    TextField(
    controller : controller,
    readOnly: true,
    )
    

    And after tapping your QR scanner button and getting your text, you can update the presented text in the TextField by the controller.

    setState((){
    controller.text = newText;
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search