I am trying to show text selection without keyboard.
It seems that triggering 'TextInput.show' always bring up keyboard.
But somehow without 'TextInput.show' I cannot select target text.
I wonder if there is alternative to select text without keyboard.
You can use TextFormFiled from flutter material package.
so first import material package to your class
import 'package:flutter/material.dart';
then create TextFormFiled in Your Widget any where you want
TextFormField(),
then create controller in top of the build method.you can control text using controller later
TextEditingController _controller = TextEditingController();
then you can hide keybord popup automatically by
TextFormField(
autofocus: false,
),
but it shows when you tap the TextFormFiled. so do you want to hide keyboard also tap state set as follows
TextFormField(
onTap: (){
FocusScope.of(context).unfocus();
},
),
Full code :
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class TestScreen extends StatelessWidget {
TextEditingController _controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextFormField(
controller: _controller,
onTap: (){
FocusScope.of(context).unfocus();
},
),
),
);
}
}
Happy Coding;
Related
The application first displays the With text: Entered text screen. And there is a button when clicked on which the user gets to another screen where he needs to enter text. It is necessary for me that when the user has entered the text, when returning back to the first screen, this text is displayed. How can this be done?
My code:
import 'package:flutter/material.dart';
class TextScreen extends StatefulWidget {
const TextScreen({Key? key}) : super(key: key);
#override
State<TextScreen> createState() => _TextScreenState();
}
class _TextScreenState extends State<TextScreen> {
final textController = TextEditingController();
#override
void dispose() {
textController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Enter data'),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: textController,
decoration: InputDecoration(labelText: 'Message'),
),
const SizedBox(
height: 20,
),
],
)),
);
}
}
You can add a result when navigating back
Navigator.of(context).pop("test");
And the you can use the result in the previos screen
Navigator.push(
context,
MaterialPageRoute(builder: (context) => TextScreen()),
).then((result) => { ... });
There are several ways to do this. The main question is if you have a specific submit action, such as a button, to confirm using the new text or if the newly entered text should always be used, also when the user uses the back button or back swipe gesture to go back to the previous screen.
Only through submit action
If you want to consider the back button as a 'cancel' operation, and only want to update the value with a specific button, you can return the new value with the Navigator: Navigator.of(context).pop(updatedValue). Where the page was pushed, you can await this result: final updatedValue = await Navigator.of(context).push(editPageRoute);
If you always want the value to update
In this case, you'll need to update this new text in a component that lives above the Navigator which is likely provided by your MaterialApp (or other WidgetApp).
To do so, you can wrap the Navigator in another widget by using the builder function of the MaterialApp. This widget can be obtained through the widget tree and is available in both pages. You can use InheritedWidget or provider to obtain this widget.
You could also keep a component outside of your widget tree that holds this text. Using get_it might be a solution for that, but riverpod would probably allow you to do so as well.
There's a button on my home page which when clicked should redirect me to another page and click on textformfield on that page,I dont know how to do that
just use autofocus: true on another page
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return NextPage();
},
));
},
child: Text("Click")),
),
);
}
}
class NextPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: TextField(
autofocus: true,
),
);
}
}
There is multiple ways to do this depending on your use case
1- if you want to focus on the text form field every time you enter the page you change autofocus property in the textField to true,
TextField(
autofocus:true,
)
2- if you want to trigger focus on a textfield by manually you can use FocusNode object, this focus node will be attached to your text field.
First you need to initialize the object.
FocusNode myFocusNode;
#override
void initState() {
super.initState();
myFocusNode = FocusNode();
}
#override
void dispose() {
// Clean up the focus node when the Form is disposed.
myFocusNode.dispose();
super.dispose();
}
then Attach the focus node object to your text field
TextField(
focusNode: myFocusNode,
);
Now you can use this focus node in a function to focus on this text
// focus on textfield (same as text field pressed)
myFocusNode.requestFocus()
// unfocus on textfield (same as pressing done on textfield or pressing the back button)
myFocusNode.unfocus()
you can pass a flag to the new page you are going to, which will trigger the focus function
Pretty much what I describe in the title. I have a pile of TextFormFields populated from Firebase when the app launches.
The user should be able to update these, and when they are done, click a submit button to update the database. The database code all works, however there is some bug which works as follows:
TextFormField1: "New Text Entered"
TextFormField2: "Some more text"
TextFormField3: "Another update here"
Now we get to a point where we need to dismiss the keyboard, so that we can see the submit button underneath. As soon as you click the little down arrow to dismiss the keyboard, all the changes above revert back to their original state.
Anyone seen this?
I am prepopulating the data in these fields at runtime, and you can edit and update the text, and it all works fine... except if you minimise the keyboard.
Please tell me that Flutter isn't doing something fundamentally stupid like reloading the widget underneath from scratch every time you ask the keyboard to go away...... It sort of feels like it is.
Yes. It happens to me all the time. It is because the screen rebuilds when the bottom insets (due to keyboard) changes.
Enclose the TextFormField(s) inside a Form and give it a global key.
Use a local variable to store the value of the TextFormField. Update it in onChanged method.
All done!
I shall attach a code for easiness.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: LoginScreen(),
);
}
}
// Login Screen
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
static GlobalKey<FormState> _loginScreenFormKey = GlobalKey<FormState>();
}
class _LoginScreenState extends State<LoginScreen> {
String username;
String password;
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Form(
key: LoginScreen._loginScreenFormKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
hintText: 'Enter username',
),
onChanged: (value) {
setState(() {
username = value;
});
},
),
TextFormField(
decoration: InputDecoration(
hintText: 'Enter username',
),
onChanged: (value) {
setState(() {
password = value;
});
},
obscureText: true,
),
RaisedButton(
onPressed: () {
LoginScreen._loginScreenFormKey.currentState.save();
},
child: Text('submit'),
),
],
),
),
),
);
}
}
This is my solution: move the TextEditingController variable from the inside of the "build" method to the outside of the "build" method. Ref in pic The solution
The class that includes those TextFormFields should extends State of StatefulWidget, the local state will be cleared if the dismiss of keyboard causes those fields re-render, hence you need StatefulWidget to save the local state so that it won't be re-rendered
Convert you StatelessWidget to StatefulWidget.
usually I can disable/grey-out a button until a TextFormField meets certain parameters in flutter by something like this:
TextFormField(
controller: _controller
value: (value)
)
SubmitButton(
onPressed: _controller.text.isNotEmpty ? _submit : null;
)
But when compiled as a website the Button seems no longer aware of the controller value...
I have tried targeting in several different ways, e.g. _controller.value.text.isEmpty and _controller.text.isEmpty...
I'm guessing I'm missing something or this method just isn't possible for web ... Is there any other way to get the same result?
To be honest, your code shouldn't work in flutter mobile either, but may be works because of screen keyboard causes widget rebuild when showing or hiding.
To fix this issue we have to use stateful widget with state variable like canSubmit and update it in textField's listener onChange with setState method. Then every time the text changes, our stateful widget will update the submit button..
class Page extends StatefulWidget {
#override
_PageState createState() => _PageState();
}
class _PageState extends State<Page> {
bool canSubmit;
#override
void initState() {
canSubmit = false;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
TextField(
onChanged: (value) {
setState(() {
canSubmit = value.isNotEmpty;
});
},
),
RaisedButton(
onPressed: canSubmit ? _submit : null,
child: Text('Submit'),
)
],
),
),
);
}
void _submit() {
print('Submitted');
}
}
Is there a way in Flutter to force that the keyboard which opens once I click the TextForm is in English?
I want a TextField to contain only English characters. Is there a way?
Use the following to open default keyboard app with predefined language.
FocusScope.of(context).requestFocus(FocusNode());
There is no way to launch the keyboard in particular language. Users have to do that from their end in keyboard settings. However you may use the RegExp to check if all the characters are in English.
May be this helps!
SystemChannels.textInput.invokeMethod('TextInput.show');
whenever requestFocus is invoked to prevent this situation:
As far as I know, there isn't a way to launch the keyboard in a language.
To open keyboard with the predefined language you need to enable autoFocus in the TextField widget like this:
TextField(
autofocus: true,
)
class _MyHomePageState extends State<MyHomePage> {
final _focusNode = FocusNode();
#override
void initState() {
super.initState();
}
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
RaisedButton(
child: Text('PROVIDE FOCUS'),
onPressed: () {
FocusScope.of(context).requestFocus(_focusNode);
SystemChannels.textInput.invokeMethod('TextInput.show');
},
),
IgnorePointer(
child: TextField(
focusNode: _focusNode,
),
)
],
),
);
}
}