Keyboard Dismisses Automatically After Typing or Removing One Character

42 Views Asked by At

I'm encountering an issue in my Flutter app where the keyboard dismisses automatically after typing or removing just one character in a TextFormField. I have a ListView.builder with Dismissible widgets containing TextFormFields. However, whenever I type or remove a character in the TextFormField, the keyboard dismisses unexpectedly.

My code:

import 'package:flutter/material.dart';
import 'package:r6stats/scanner_result.dart';

class PlayerEditor extends StatefulWidget {
  const PlayerEditor({super.key, required this.playerNames});

  final List<String> playerNames;

  @override
  State<PlayerEditor> createState() => _PlayerEditorState();
}

class _PlayerEditorState extends State<PlayerEditor> {

  @override
  Widget build(BuildContext context) {
    List<String> players = widget.playerNames;

    return Scaffold(
      appBar: AppBar(
        title: const Text("Edit Players"),
        actions: [
          IconButton(
              onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (context) => ScannerResult(playerNames: players),
                  ),
                );
              },
              icon: const Icon(Icons.check))
        ],
      ),
      body: ListView.builder(
        itemCount: players.length,
        itemBuilder: (context, index) => Padding(
          padding: const EdgeInsets.all(8),
          child: Dismissible(
            key: UniqueKey(),
            direction: DismissDirection.startToEnd,
            onDismissed: (direction) {
              final playerName = players[index];
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                content: Text("${players[index]} dismissed"),
                action: SnackBarAction(
                  label: 'UNDO',
                  onPressed: () {
                    setState(() {
                      players.insert(index, playerName);
                    });
                  },
                ),
              ));
              setState(() {
                players.removeAt(index);
              });
            },
            background: Container(
              color: Colors.red,
              alignment: Alignment.centerLeft,
              padding: const EdgeInsets.only(left: 20.0),
              child: const Icon(Icons.delete, color: Colors.white),
            ),
            child: ListTile(
              tileColor: const Color.fromRGBO(194, 194, 194, 100),
              shape: const RoundedRectangleBorder(
                  side: BorderSide(color: Colors.black, width: 1)),
              title: TextFormField(
                initialValue: players[index],
                onChanged: (newValue) {
                  setState(() {
                    players[index] = newValue;
                  });
                },
                style: Theme.of(context)
                    .textTheme
                    .titleMedium!
                    .copyWith(color: Colors.black),
                decoration: const InputDecoration(
                  border: InputBorder.none,
                  focusedBorder: InputBorder.none,
                  hintText: 'Enter player name',
                ),
              ),
              titleTextStyle: Theme.of(context)
                  .textTheme
                  .titleMedium!
                  .copyWith(color: Colors.black),
            ),
          ),
        ),
      ),
    );
  }
}

I've tried using GlobalKey for the ListView.builder and UniqueKey for each Dismissible widget, but the issue persists. How can I prevent the keyboard from dismissing automatically after typing or removing a character?

Any insights or suggestions would be greatly appreciated. Thank you!

2

There are 2 best solutions below

2
Warjeh On

I think there might be two problems with your code.

  1. Since you are changing the list of players, and you can not change the value of widget.playerNames, you must copy the List items. So, do this:
List<String> players = [...widget.playerNames];
  1. You don't need to use setState in your onChanged method.
0
Dewa Prabawa On

I try to fix the two issues here, 1. Your playerNames list is a final list which is not okay to modify. 2. I removed the setState from your textFormField that I may cause the problem of keyboard dismisses.automatically.

import 'package:flutter/material.dart';
import 'package:r6stats/scanner_result.dart';

class PlayerEditor extends StatefulWidget {
  const PlayerEditor({super.key, required this.playerNames});

  final List<String> playerNames;

  @override
  State<PlayerEditor> createState() => _PlayerEditorState();
}

class _PlayerEditorState extends State<PlayerEditor> {
  
  List<String> players = [];
  
    @override
  void initState() {
    super.initState();
    players = List<String>.from(widget.playerNames);
  }


  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
      appBar: AppBar(
        title: const Text("Edit Players"),
        actions: [
          IconButton(
              onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (context) => ScannerResult(playerNames: players),
                  ),
                );
              },
              icon: const Icon(Icons.check))
        ],
      ),
      body: ListView.builder(
        itemCount: players.length,
        itemBuilder: (context, index) => Padding(
          padding: const EdgeInsets.all(8),
          child: Dismissible(
            key: UniqueKey(),
            direction: DismissDirection.startToEnd,
            onDismissed: (direction) {
              final playerName = players[index];
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                content: Text("${players[index]} dismissed"),
                action: SnackBarAction(
                  label: 'UNDO',
                  onPressed: () {
                    setState(() {
                      players.insert(index, playerName);
                    });
                  },
                ),
              ));
              setState(() {
                players.removeAt(index);
              });
            },
            background: Container(
              color: Colors.red,
              alignment: Alignment.centerLeft,
              padding: const EdgeInsets.only(left: 20.0),
              child: const Icon(Icons.delete, color: Colors.white),
            ),
            child: ListTile(
              tileColor: const Color.fromRGBO(194, 194, 194, 100),
              shape: const RoundedRectangleBorder(
                  side: BorderSide(color: Colors.black, width: 1)),
              title: TextFormField(
                initialValue: players[index],
                onChanged: (newValue) {
                  players[index] = newValue;
                },
                style: Theme.of(context)
                    .textTheme
                    .titleMedium!
                    .copyWith(color: Colors.black),
                decoration: const InputDecoration(
                  border: InputBorder.none,
                  focusedBorder: InputBorder.none,
                  hintText: 'Enter player name',
                ),
              ),
              titleTextStyle: Theme.of(context)
                  .textTheme
                  .titleMedium!
                  .copyWith(color: Colors.black),
            ),
          ),
        ),
      ),
    );
  }
}