kavakliri
kavakliri

Reputation: 13

How to set focus to TextField in ListView

I have a ListView that has a TextField widget in its children. Listview's items can be changed dynamically. When I press the "Add row" button, a new row should be added and the textfield belongs to newly added row should be focused (keyboard should be shown.) How can I achieve this?

Here is my sample code:

import 'package:flutter/material.dart';

class MainPage extends StatefulWidget {
  MainPage({Key key}) : super(key: key);
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  List<String> list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('NoteList App'),
        ),
        body: Column(children: <Widget>[
          Expanded(child: _buildList(context)),
          FlatButton(
              onPressed: () {
                setState(() {
                  list.add('new');
                });
              },
              child: Text('Add row'))
        ]));
  }

  Widget _buildList(BuildContext context) {
    return ListView.builder(
      itemCount: list.length,
      padding: const EdgeInsets.only(top: 1.0),
      itemBuilder: (context, index) {
        return ListItem(textContent: list[index]);
      },
    );
  }
}

class ListItem extends StatelessWidget {
  var _txt = TextEditingController();
  final String textContent;

  ListItem({Key key, this.textContent}) : super(key: key) {
    _txt.text = textContent ?? '';
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: _txt,
      textInputAction: TextInputAction.go,
    );
  }
}

Upvotes: 1

Views: 4787

Answers (1)

chunhunghan
chunhunghan

Reputation: 54377

You can copy paste run full code below
You can define an Item class and put FocusNode in it
then use FocusScope.of(context).requestFocus

code snippet

class Item {
  String textContent;
  FocusNode myFocusNode;
  TextEditingController myController;

  Item(this.textContent, this.myFocusNode, this.myController);
}


List<Item> list = [
  Item('one', FocusNode(), TextEditingController()),
  Item('two', FocusNode(), TextEditingController()),
  Item('three', FocusNode(), TextEditingController()),
  Item('four', FocusNode(), TextEditingController())
];

onPressed: () {
                setState(() {
                  list.add(Item('new', FocusNode(), TextEditingController()));
                });

                WidgetsBinding.instance.addPostFrameCallback((_) {
                  FocusScope.of(context)
                      .requestFocus(list[list.length - 1].myFocusNode);
                });
              },

working demo

enter image description here

full code

import 'package:flutter/material.dart';

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

class Item {
  String textContent;
  FocusNode myFocusNode;
  TextEditingController myController;

  Item(this.textContent, this.myFocusNode, this.myController);
}

class MainPage extends StatefulWidget {
  MainPage({Key key}) : super(key: key);
  _MainPageState createState() => _MainPageState();
}

List<Item> list = [
  Item('one', FocusNode(), TextEditingController()),
  Item('two', FocusNode(), TextEditingController()),
  Item('three', FocusNode(), TextEditingController()),
  Item('four', FocusNode(), TextEditingController())
];

class _MainPageState extends State<MainPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('NoteList App'),
        ),
        body: Column(children: <Widget>[
          Expanded(child: _buildList(context)),
          FlatButton(
              onPressed: () {
                setState(() {
                  list.add(Item('new', FocusNode(), TextEditingController()));
                });

                WidgetsBinding.instance.addPostFrameCallback((_) {
                  FocusScope.of(context)
                      .requestFocus(list[list.length - 1].myFocusNode);
                });
              },
              child: Text('Add row'))
        ]));
  }

  Widget _buildList(BuildContext context) {
    return ListView.builder(
      itemCount: list.length,
      padding: const EdgeInsets.only(top: 1.0),
      itemBuilder: (context, index) {
        return ListItem(index: index);
      },
    );
  }

  @override
  void dispose() {
    list.forEach((element) {
      element.myFocusNode.dispose();
      element.myController.dispose();
    });

    super.dispose();
  }
}

class ListItem extends StatefulWidget {
  final int index;

  ListItem({Key key, this.index}) : super(key: key);

  @override
  _ListItemState createState() => _ListItemState();
}

class _ListItemState extends State<ListItem> {
  @override
  void initState() {
    super.initState();
    list[widget.index].myController.text = list[widget.index].textContent;
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      focusNode: list[widget.index].myFocusNode,
      controller: list[widget.index].myController,
      textInputAction: TextInputAction.go,
    );
  }
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MainPage(),
    );
  }
}

Upvotes: 5

Related Questions