I do not see a blinking cursor if I enable and focus a previous disabled TextFormField. In this example, the TextFormField is originally disabled, as indicated by the _enabled state variable, and when you click on the enable button, the field is enabled and focused but the blinking cursor is not visible. I have to click on the TextFormField in order to see the blinking cursor.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
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: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _enabled = false;
FocusNode focusNodeA = FocusNode();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: TextFormField(
enabled: _enabled,
focusNode: focusNodeA,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() => _enabled = true);
FocusScope.of(context).requestFocus(focusNodeA);
},
child: Text('Enable'),
),
);
}
}
If I press 'Enable' twice, the cursor is shown.
If the TextFormField was already enabled and then focused, the blinking cursor is visible.
1- you focused after setState so it not working.
just do like below
2- you can't focus widget until disabled and when you enabling widget. when you do focusing and enabling at same time in ui tread it's try focusing before enabling because of their rendering time.if you post some delay to focusing the problem get solving.
setState(() {
Future.delayed(const Duration(milliseconds: 10), ()
{
FocusScope
.of(
context)
.requestFocus(
focusNodeA);
print(FocusScope.of(context).focusedChild.toString());
});
_enabled = true;
});
Please try
setState(() {
enableEditText = true;
Future.delayed(const Duration(milliseconds: 500), () {
tfController.selection =
TextSelection.fromPosition(TextPosition(offset: tfController.text.length));
FocusScope.of(context).requestFocus(focusNode);
});
});
TextField(
controller: tfController,
decoration: null,
textInputAction: TextInputAction.done,
enabled: enableEditText,
focusNode: focusNode,
),
Related
i have textField and triger the focus by button, but when i dismis the keyboard and i try to click the button for second time the keyboard is does not showing up, because the textfield still focused
onTap: () {
FocusScope.of(context).requestFocus(controller.textFieldFocus);
},
I think I found a working solution, (currently only tested on android emulator).
This is a small working example:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late FocusNode node;
#override
void initState() {
super.initState();
node = FocusNode();
}
#override
void dispose() {
node.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Focus Demo'),
actions: [
TextButton(
onPressed: () {
node.unfocus();
WidgetsBinding.instance?.addPostFrameCallback((_) {
FocusScope.of(context).requestFocus(node);
});
},
child: Text(
'Focus',
style: Theme.of(context).primaryTextTheme.bodyText1,
),
),
],
),
body: TextField(
focusNode: node,
),
),
);
}
}
I was able to get it working by adding a delay between the unfocusing and refocusing using WidgetsBinding.instance?.addPostFrameCallback.
In your case that should translate to something like this:
onTap: () {
controller.textFieldFocus.unfocus();
WidgetsBinding.instance?.addPostFrameCallback((_) {
FocusScope.of(context).requestFocus(controller.textFieldFocus);
});
},
I have some next (simplified) widget-tree structures:
- home (stack of widgets)
- page container
- editText field
As you can see, edit text will be always on top of the pages, which I will swap with Navigator.of(context) transactions.
The problem: when I focus editText the keyboard appears. When user starts typing, at some moment, I need to push another screen inside the page container. And when I use Navigator.of() - editText is unfocused and the keyboard goes down.
Whats needed: I need somehow to do transition (push/pop/replace) in page container with the Navigator and keep keyboard still up (keep editText focused).
Do you have any knowledge of how to do that?
Your use case looks really weird but I suppose you have a good reason to follow this setup.
Anyway the issue is that when Navigator.push is called, the TextField is unfocused. This is not a bug but rather an intended feature which (I think) is here to prevent a keyboard to follow you to the next screen where no TextField would be present. However I understand that this is an issue for your use case.
My solution (not the prettiest I would admit, but the only thing I could have working) is to force the focus back to the TextField manually. You need two component:
A FocusNode to associate to your TextField to listen to check if your TextField changes from focus to unfocused. If the focusOnNextUnfocus is set, it should re-request the focus after an unfocus
focusOnNextUnfocus a bool to set to true just before pushing, and which will be set to false once the focus has been requested again.
Here is the adaptation of the code you provided:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
/// Handles the focus state of our text field
final focusNode = FocusNode();
/// A bool to keep track on whether we should refocus after
/// unfocus. This will be set to `true` before pushing
var focusOnNextUnfocus = false;
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
void initState() {
focusNode.addListener(() {
// If we no longer have the focus and should refocus, we refocus
if (!focusNode.hasFocus && focusOnNextUnfocus) {
focusNode.requestFocus();
focusOnNextUnfocus = false; // Reset to false once it has been processed
}
});
super.initState();
}
#override
void dispose() {
focusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
late BuildContext anotherContext;
final edit = TextField(
focusNode: focusNode,
onChanged: (String value) async {
if (value.length > 4) {
// Pop does not unfocus so no worries here
Navigator.pop(anotherContext);
} else if (value.length > 3) {
// Push DOES unfocus, so we need to set focusOnNextUnfocus to true
focusOnNextUnfocus = true;
Navigator.of(anotherContext).push(
MaterialPageRoute(builder: (_) {
return Builder(builder: (context) {
return Another();
});
}),
);
}
},
);
final scaffold = MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Builder(
builder: (context) {
anotherContext = context;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
);
return Scaffold(
body: Stack(
children: [
Positioned(child: scaffold),
Align(
alignment: Alignment.center,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: edit,
),
),
],
),
);
}
}
class Another extends StatelessWidget {
const Another({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
);
}
}
How can a button disable a TextField, so when I click the button I can't change the TextField's value?
You should change the TextField enabled property to false when the button is pressed. Here is an example:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: Center(
child: MyStatefulWidget(),
),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
#override
_State createState() => _State();
}
class _State extends State<MyStatefulWidget> {
bool isTextFieldEnabled = true;
#override
Widget build(BuildContext context) {
return Container(
child: Column(children: [
TextField(enabled: isTextFieldEnabled,),
ElevatedButton(child: Text('Press Me To Disable TextField'),
onPressed: () {
setState(() {
isTextFieldEnabled = false;
});
},),
],)
);
}
}
you can use enabled false on text field:
TextField(
keyboardType: TextInputType.number,
enabled: false,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Current Miles',
),
),
but if you still want to handle a click on your text field you should use follow:
TextField(
readOnly: true,
enableInteractiveSelection: true,
onTap: () {
do_something(),
},
),
you need to use 'setState' on you button 'onPressed' and put any of the above needed flags in a variable and set accordingly.
Both TextField and TextFormField has a property called enabled, it's a bool, also you need to add a controller, and this can be achieved controlled by :
bool? enabled;
TextFormField(
enabled:enabled
)
//for the button
GestureDetector(onTap: () {
setState(() {
enabled = false;
});
})
I am new to Flutter.
If I click a check box action should be performed.
Eg: Click a checkbox, enable the other checkbox and enable a text field
disable or enable widget only for button click is available.
I don't know how to do it in flutter
The idea is to use ternary operator ( ? : ) this works same as if does. Most basic explanation about code below when the checkbox is triggered checkBox1 changes and widget rebuilds with checkBox1 equals true now so instead of empty Container currently we are building new CheckBox.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool checkBox1 = false;
bool checkBox2 = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
CheckboxListTile(
title: Text("title text"),
value: checkBox1,
onChanged: (newValue) {
setState(() {
checkBox1 = newValue;
});
},
),
checkBox1
? CheckboxListTile(
title: Text("title text2"),
value: checkBox2,
onChanged: (newValue) {
setState(() {
checkBox2 = newValue;
});
},
)
: Container(),
],
),
);
}
}
final TextEditingController _controllerTE =
TextEditingController();
bool cbFlag = false;
TextField(
readOnly: !cbFlag,
controller: _controllerTE,
decoration: InputDecoration(
labelText: 'TE disabled till CB checked',
prefixIcon: Checkbox(
value: cbFlag,
onChanged: (bool? value) {
setState(() {
cbFlag = value!;
});
},
),
),
),
I have a Textfield and after the input I want to convert the Textfield widget into a simple Textwidget (e.g. input your name => displays your name).
I tried doing this with a conditional statement in this code below (it's just a quick sample code to display the problem, didn't want to post my whole code):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController hello1 = TextEditingController();
int counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
hello1.text == ''
? TextField(
controller: hello1, onSubmitted: (_) => print(hello1.text))
: Text(hello1.text),
RaisedButton(onPressed: () {
setState(() {
counter++;
});
})
],
),
),
);
}
}
So when I enter the text into the Textfield and submit it, the widget will not convert into a text widget. Unless I rerender something else on the screen, that's why I added the RaisedButton and the counter variable.
So what can I do to convert it immediately into a text widget.
Feel free to point me to some fundamental logic I might be missing here, thank you!
It's because you don't call the setState() method.
Changing the value of the TextEditingController won't rebuild your widget.
SetState() method does.
children: <Widget>[
hello1.text == ''
? TextField(
controller: hello1,
onSubmitted: (_) {
print(hello1.text);
setState(() {});
},
)
: Text(hello1.text),
RaisedButton(
onPressed: () {
setState(() {});
},
)
],