I have a test edit field. When there is no text, I want a button disabled. When there is text in the TextField, I want the button enabled.
I am using flutter_hooks to reduce boiler plate code for controllers.
In the following example, when I enter test into the text field, the button never enables, because build is not triggered? How can I trigger a build when using a text editing controller with flutter hooks?
class MyHomePage extends HookWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var ctrl = useTextEditingController();
VoidCallback? onPressed;
if (ctrl.text.isNotEmpty) {
onPressed = () => print("Pressed!");
}
return Scaffold(
body: Column(
children: [
TextField(
controller: ctrl,
),
ElevatedButton(onPressed: onPressed, child: Text("Button")),
],
)
);
}
}
CodePudding user response:
To rebuild you widget use a useEffect
Hook. The Hook takes a function callback as a parameter and runs side effects in a widget.
useEffect
is called synchronously on every build, unless keys is specified. In which case useEffect
is called again only if any value inside keys as changed.
Change your code like below
class MyHomePage extends HookWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final ctrl = useTextEditingController(text: '');
VoidCallback? onPressed;
final fieldsIsEmpty =
useState<bool>(true);
bool fieldsEmpty() {
return ctrl.text.toString().isEmpty
}
useEffect(() {
ctrl.addListener(() {
fieldsIsEmpty.value = fieldsEmpty();
});
}, [
ctrl
]);
return Column(
children: [
TextField(
controller: ctrl,
),
fieldsIsEmpty.value ? const ElevatedButton(
child: Text('Disabled'),
onPressed: null,
): ElevatedButton(
child: const Text('Enabled'),
onPressed: onPressed,
)
],
);
}
}
CodePudding user response:
You can Achieve this using useState
and useTextEditingController
var istextchanged = useState<bool>(false);
ctrl.addListener(() {
if (ctrl.text.isEmpty) {
istextchanged.value = false;
} else {
istextchanged.value = true;
}
});
Yourwidget
class MyHomePages2 extends HookWidget {
const MyHomePages2({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var ctrl = useTextEditingController();
var istextchanged = useState<bool>(false);
ctrl.addListener(() {
if (ctrl.text.isEmpty) {
istextchanged.value = false;
} else {
istextchanged.value = true;
}
});
VoidCallback? onPressed = () {
print("change");
};
if (ctrl.text.isNotEmpty) {
onPressed = () => print("Pressed!");
}
return Scaffold(
body: Column(
children: [
TextField(
controller: ctrl,
onChanged: (v) {},
),
ElevatedButton(
onPressed: istextchanged.value ? onPressed : null,
child: Text("Button"))
],
));
}
}
Package used flutter_hooks: ^0.18.2 1
pub.dev/flutter_hooks
SampleCode
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
int myvalue = 0;
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
void initState() {
// functions().then((int value) {
// setState(() {
// myvalue = value;
// });
// future is completed you can perform your task
// });
}
Future<int> functions() async {
// do something here
return Future.value();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: MyHomePages2(),
);
}
}
class MyHomePages2 extends HookWidget {
const MyHomePages2({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var ctrl = useTextEditingController();
var istextchanged = useState<bool>(false);
ctrl.addListener(() {
if (ctrl.text.isEmpty) {
istextchanged.value = false;
} else {
istextchanged.value = true;
}
});
VoidCallback? onPressed = () {
print("change");
};
if (ctrl.text.isNotEmpty) {
onPressed = () => print("Pressed!");
}
return Scaffold(
body: Column(
children: [
TextField(
controller: ctrl,
onChanged: (v) {},
),
ElevatedButton(
onPressed: istextchanged.value ? onPressed : null,
child: Text("Button"))
],
));
}
}