Reputation: 13
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
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
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