Reputation: 5141
I have a reusable text field class like so:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String value = "";
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: MyTextField(
value: value,
onChange: (val) {
setState(() {
value = val;
});
},
),
),
),
);
}
}
typedef ChangeCallback = void Function(String value);
class MyTextField extends StatefulWidget {
final ChangeCallback onChange;
final String value;
const MyTextField({this.onChange = _myDefaultFunc, this.value = ""});
static _myDefaultFunc(String value){}
@override
_MyTextFieldState createState() => _MyTextFieldState();
}
class _MyTextFieldState extends State<MyTextField> {
final controller = TextEditingController();
@override
void initState() {
controller.text = widget.value;
super.initState();
}
@override
void didUpdateWidget(covariant MyTextField oldWidget) {
controller.text = widget.value;
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
onChanged: (value) {
widget.onChange(value);
},
);
}
}
As you can see, if the value is changed then onChange
callback is called and also the value is again sent back to TextField
. The problem with this is every time I update the value, TextField
sets the cursor always to the start. Probably because the updated value is sent back to the TextField
everytime? Not sure. Can you help me with this?
Upvotes: 2
Views: 698
Reputation: 7105
No need to update values in didUpdateWidget
//@override
// void didUpdateWidget(covariant MyTextField oldWidget) {
// controller.text = widget.value;
// super.didUpdateWidget(oldWidget);
// }
I just commented-out this function and the code works fine below is the complete code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String value = "";
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(children: [
SizedBox(height:50),
Text("text input: $value"),
SizedBox(height:50),
Center(
child: MyTextField(
value: value,
onChange: (val) {
setState(() {
value = val;
});
},
),
),
]),
),
);
}
}
typedef ChangeCallback = void Function(String value);
class MyTextField extends StatefulWidget {
final ChangeCallback onChange;
final String value;
const MyTextField({this.onChange = _myDefaultFunc, this.value = ""});
static _myDefaultFunc(String value) {}
@override
_MyTextFieldState createState() => _MyTextFieldState();
}
class _MyTextFieldState extends State<MyTextField> {
final controller = TextEditingController();
@override
void initState() {
controller.text = widget.value;
super.initState();
}
// @override
// void didUpdateWidget(covariant MyTextField oldWidget) {
// controller.text = widget.value;
// super.didUpdateWidget(oldWidget);
// }
@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
onChanged: (value) {
widget.onChange(value);
},
);
}
}
Upvotes: 1
Reputation: 18750
Instead of using onChanged
method to get the value of text field, pass a TextEditingController
.
class MyTextField extends StatefulWidget {
final TextEditingController controller;
final String defaultValue;
const MyTextField({@required this.controller, this.defaultValue = ''});
@override
_MyTextFieldState createState() => _MyTextFieldState();
}
class _MyTextFieldState extends State<MyTextField> {
@override
void initState() {
widget.controller.text = widget.defaultValue;
super.initState();
}
@override
Widget build(BuildContext context) {
return TextField(
controller: widget.controller,
);
}
}
This way, you can declare a TextEditingController
in the parent widget to get the value like you would normally do with Flutter's native TextFormField
.
Upvotes: 1