This is my screen with TextField and Button. When someone clicks on show button, I want it to show the name below the button as shown in below picture.
Code below:
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo> {
final name = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Row(
children: [
Text(
'Name'
),
TextField(
controller: name,
)
],
),
RaisedButton(
onPressed: (){
},
child: Text('Show'),
)
],
),
),
);
}
}
This can be a basic example for your question. The UI is not exactly what you've shown above
class Question extends StatefulWidget {
Question({Key key}) : super(key: key);
#override
_QuestionState createState() => _QuestionState();
}
class _QuestionState extends State<Question> {
String text = '';
bool shouldDisplay = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
Center(
child: TextField(
onChanged: (value) {
setState(() {
text = value;
});
},
),
),
FlatButton(onPressed: () {
setState(() {
shouldDisplay = !shouldDisplay;
});
}, child: Text('Submit')),
shouldDisplay ? Text(text) : Spacer()
],
);
}
}
Hope this helps.
Initialize two variables. One for a TextEditingController and one for the text value.
TextEditingController controller = TextEditingController();
String display = '';
Give your TextField a controller.
TextField(controller:controller);
In your button, set onPressed to change display text to the controller text.
FlatButton(
child: Text("Show"),
onPressed()=> setState((){display = controller.text;});
),
Then where you want to show the text, set the text string to display.
Text(display);
I would advice you to learn the basics of flutter first before asking these kinds of questions. This can be simply achieved through using TextEditingController and setState(). Simply define a controller for your TextField and then call setState() when your button is pressed. Note that you have to be on a StatefulWidget since calling setState() rebuilds the UI.
Create a TextEditingController and string above the #override Widget build:
String displayName="";
final myController = TextEditingController();
Create a TextField and add assign the controller to it:
TextField(
controller: myController,
);
Call setState() on button pressed:
MaterialButton(
child: Text("Show"),
onPressed: (){
setState(() {
displayName=myController.text;
});
})
Display it using a Text widget:
Text(displayName);
Good Luck!
You can find out how to use TextEditingController here: https://flutter.dev/docs/cookbook/forms/retrieve-input
More about widgets here: https://www.youtube.com/playlist?list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG
Related
I would like to get the value of the dropdown from the other widget in the real estate app. Say I have two widgets. First one is the dropdown widget, and the second one is Add New Property widget (or a page).. I would like to access the value of the dropdown from the Add New Property.
I could achieve this with final Function onChanged; but Im wondering if there is another way to achieve with the Provider package or the ValueNotifier
the code below is my Dropdown button widget
class PropertyType extends StatefulWidget {
final Function onChanged;
const PropertyType({
super.key,
required this.onChanged,
});
#override
State<PropertyType> createState() => _PropertyTypeState();
}
class _PropertyTypeState extends State<PropertyType> {
final List<String> _propertyTypeList = propertyType;
String? _propertyType = 'No Info';
#override
Widget build(BuildContext context) {
return ANPFormContainer(
fieldTitle: 'Property Type',
subTitle: 'အိမ်ခြံမြေအမျိုးအစား',
child: FormBuilderDropdown<String>(
name: 'a2-propertyType',
initialValue: _propertyType,
items: _propertyTypeList
.map(
(itemValue) => DropdownMenuItem(
value: itemValue,
child: Text(itemValue),
),
)
.toList(),
onChanged: (val) {
setState(() {
_propertyType = val;
widget.onChanged(val);
});
},
),
);
}
}
And this is the "Add New Property" form page
class ANPTest extends StatefulWidget {
const ANPTest({super.key});
#override
State<ANPTest> createState() => _ANPTestState();
}
class _ANPTestState extends State<ANPTest> {
final TextEditingController _propertyid = TextEditingController();
String _propertyType = 'No Info';
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ZayyanColorTheme.zayyanGrey,
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
PropertyID(propertyID: _propertyid),
PropertyType(onChanged: (String value) {
_propertyType = value;
}),
addVerticalSpacer(25),
ANPNextButton(onPressed: _onpressed),
],
),
),
);
}
_onpressed() {
final anp = MdlFirestoreData(
propertyid: _propertyid.text, propertyType: _propertyType)
.toFirestore();
FirebaseFirestore.instance.collection('Selling Posts').add(anp);
}
}
Thank you for helping me out.
Best
yes, you could use Getx or provider package by creating a controller(function) and the package helps you to have access to variables in
your controller to use them everywhere in your program,
you may need to learn about Getx
it can help you manage your navigation and state
What is the best way to show a widget after an action? In my case, I want to show the Text Forgot Password? after the user misses the login credentials so he get's the option for reset password or to be sent his password through email.
Picture1:
And the second picture after the user missed the password, an action triggers and the Forgot Password appears:
I've thought of using AnimatedOpacity() but not sure if this is the right approach. Thanks in advance for the advice.
This is a minimal working code, that delivers the message. You can use setState.
in your stateful widget.
import 'package:flutter/material.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController _email = TextEditingController();
TextEditingController _password = TextEditingController();
bool _forgotPassword = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: _email,
),
TextField(
controller: _password,
),
_forgotPassword
? TextButton(
onPressed: () async {
//await your logic for forgotton password
},
child: Text('Forgot Password'))
: Container(),
TextButton(
onPressed: () async {
//await your login logic, if it returns false\error\not authenticated, then you can change the state of _forgotPassword, and then shows 'forgot password TextButton'
setState(() {
_forgotPassword = true;
});
},
child: Text('Login'))
],
);
}
}
You can use state management to show or hide any widget on any action. See the example below, read the explanation in the inline comment.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget{
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool showcard = false; //set widget show to false
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text("Show widget on action"), //title of app
backgroundColor: Colors.redAccent, //background color of app bar
),
body: Container(
child: Column(children: [
showcard?Container( //check if showcard is true or false
child: Card(
child: Padding(
padding: EdgeInsets.all(20),
child:Text("This is card widget")
)
)
):Container(),
//if showcard is true then show card, else show empty contianer.
Container(
child: ElevatedButton(
child: Text(showcard?"Hide Card":"Show Card"),
onPressed: (){
setState(() { //update UI with setState
if(showcard){
showcard = false;
//if showcard is true, then make it false to hide
}else{
showcard = true;
//if showcard is false, then make it true to show.
}
});
},
)
)
],)
)
);
}
}
In this example, there is raised button, when you click on it, the card will appear, and there will be "hide" button, and when you click on it, the card will disappear, or vice versa.
Output:
Card widget after pressing "show card" button.
Here's a very simple code sample on how to do it using the Visibility widget.
import 'package:flutter/material.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController();
bool showForgotPassword = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: emailController,
),
TextField(
controller: passwordController,
),
Visibility(
child: Text("Forgot Password?"),
visible: showForgotPassword,
),
RaisedButton(
child: Text("Log in"),
onPressed: () {
// Validate password
if (passwordController.text != 'realpassword') {
setState(() {
showForgotPassword = true;
});
} else {
// continue
}
},
),
],
);
}
}
When we click the login button with the wrong password. We change the visible property of the Visibility widget to true. Hence, the password text becomes visible.
If we type the correct password, then the visible property of the Visibility widget becomes false. Hence, the text becomes invisible.
OUTPUT
When they put the wrong password:
When they put the correct password:
import 'package:flutter/material.dart';
class Demo {
int no;
String value;
Demo({this.value, this.no});
}
class Control {
TextEditingController controller;
FocusNode node;
Control({this.controller, this.node});
}
class DemoPage extends StatefulWidget {
static const routeName = '/Demo';
DemoPage({Key key}) : super(key: key);
#override
_DemoPageState createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
List<Demo> txtfield;
List<Control> control;
#override
void initState() {
txtfield = [];
control = [];
// no = 0;
add();
super.initState();
}
int no;
void add() {
no = (no ?? 0) + 1;
setState(() {});
txtfield.add(Demo(no: no));
control.add(Control(
controller: TextEditingController(),
node: FocusNode(),
));
// no = no +1;
}
#override
Widget build(BuildContext context) {
// print(txtfield[0].no);
// FocusScope.of(context).requestFocus(control[control.length - 1].node);
return Scaffold(
appBar: AppBar(),
body: Center(
child: Card(
child: Container(
child: Column(
children: txtfield
.map((f) => TextField(
controller: control[f.no - 1].controller,
focusNode: control[f.no - 1].node,
autofocus: true,
))
.toList(),
),
width: 400,
padding: EdgeInsets.all(20),
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
add();
print(no);
FocusScope.of(context).requestFocus(control[control.length - 1].node);
},
),
);
}
}
I used above code. but I can't able to focus on a newly added text field.
when I check for that newly added text field has focus, it shows true, but I can't able to write anything in that text field.
I don't know what is an error in that code.
I search for this solution for more than 4 days. but I can't able to find solution.
At the onPressed of your floatingActionButton change this line:
FocusScope.of(context).requestFocus(control[control.length - 1].node);
with this
control[control.length - 1].node.requestFocus();
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');
}
}
With my current code the TextField becomes focused, but the cursor and keyboard aren't triggered (requires a second tap). I believe this is because the TextField doesn't exist when the focus node is initially focused, but I'm struggling to find a solution.
Here is a simple recreation of the problem based on a Cookbook recipe:
class MyCustomForm extends StatefulWidget {
#override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
FocusNode myFocusNode;
bool _editingField2 = false;
#override
void initState() {
super.initState();
myFocusNode = FocusNode();
myFocusNode.addListener(_focusListener);
}
#override
void dispose() {
myFocusNode.dispose();
super.dispose();
}
// Set _editingField2 to true when focusNode has focus.
_focusListener() {
if (myFocusNode.hasFocus) {
setState(() {
_editingField2 = true;
});
} else {
setState(() {
_editingField2 = false;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Text Field Focus'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// The first text field is focused on as soon as the app starts.
TextField(
autofocus: true,
),
// The second text field is created when _editingField2 (after FAB press).
_editingField2
? TextField(
focusNode: myFocusNode,
)
: Text('ayy'),
],
),
),
floatingActionButton: FloatingActionButton(
// Give focus node focus on FAB press.
onPressed: () => FocusScope.of(context).requestFocus(myFocusNode),
tooltip: 'Focus Second Text Field',
child: Icon(Icons.edit),
),
);
}
}
Here is my code, with important bits commented.
class TaskListItem extends StatefulWidget {
final Task task;
TaskListItem({#required this.task});
#override
State createState() => _TaskListItemState();
}
class _TaskListItemState extends State<TaskListItem> {
bool _isEditing;
FocusNode _focusNode;
final TextEditingController _textEditingController = TextEditingController();
#override
initState() {
super.initState();
_isEditing = false;
_textEditingController.text = widget.task.text;
_textEditingController.addListener(_handleTextFieldUpdate);
_focusNode = FocusNode(debugLabel: 'TaskListItem');
_focusNode.addListener(_handleFocusChange);
}
#override
void dispose() {
_focusNode.removeListener(_handleFocusChange);
_focusNode.dispose();
_textEditingController.dispose();
super.dispose();
}
_handleTextFieldUpdate() {
Provider.of<TaskListModel>(context, listen: false)
.updateTaskText(widget.task, _textEditingController.text);
}
// Update state to determine if Text or TextField widget is created in build().
_handleFocusChange() {
if (_focusNode.hasFocus) {
setState(() {
_isEditing = true;
});
} else {
setState(() {
_isEditing = false;
});
}
}
Widget _buildTitle() {
return Row(
children: <Widget>[
Expanded(
// Create either TextField or Text based on _isEditing value.
child: _isEditing && !widget.task.isComplete
? TextField(
focusNode: _focusNode,
controller: _textEditingController,
)
: Text(
widget.task.text,
style: widget.task.isComplete
? TextStyle(decoration: TextDecoration.lineThrough)
: null,
),
),
],
);
}
#override
Widget build(BuildContext context) {
return ListTile(
leading: Checkbox(
value: widget.task.isComplete,
//Dismiss focus when box is checked
onChanged: (bool checked) {
_focusNode.unfocus();
Provider.of<TaskListModel>(context, listen: false)
.toggleComplete(widget.task);
},
),
title: _buildTitle(),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => Provider.of<TaskListModel>(context, listen: false)
.deleteTask(widget.task),
),
onTap: () {
// I'm requesting focus here, but the Textfield doesn't exist yet?
FocusScope.of(context).requestFocus(_focusNode);
print('tapped');
},
);
}
}
What you have to do is change focus inside build, you're trying to change focus before the screen has done rebuilding that widget already. try this please, using your own code.
I'm not sure if you needed to really listen to that focus change or if you only wanted to accomplish the focus change after enabling the widget, if you do want to listen for the focus change let me know.
class MyCustomForm extends StatefulWidget {
#override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
FocusNode myFocusNode = FocusNode();
bool _editingField2 = false;
#override
void dispose() {
myFocusNode?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
//here you do the focus request
if (_editingField2) {
FocusScope.of(context).requestFocus(myFocusNode);
}
return Scaffold(
appBar: AppBar(
title: Text('Text Field Focus'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// The first text field is focused on as soon as the app starts.
TextField(
autofocus: true,
),
// The second text field is created when _editingField2 (after FAB press).
_editingField2
? TextField(
focusNode: myFocusNode,
)
: Text('ayy'),
],
),
),
floatingActionButton: FloatingActionButton(
// Give focus node focus on FAB press.
onPressed: () {
setState(() {
_editingField2 = true;
});
},
tooltip: 'Focus Second Text Field',
child: Icon(Icons.edit),
),
);
}
}