I want to make a Password TextField in which the content visibility can be controlled by the suffix icon.
The code may like this:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
runApp(TestGetX());
}
class TestGetX extends StatelessWidget {
var eyeClosed = true.obs;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Test GetX"),
),
body: Align(
alignment: Alignment.center,
child: Padding(
padding: EdgeInsets.all(20),
child: TextFormField(
obscureText: eyeClosed.value,
decoration: InputDecoration(
icon: Icon(
Icons.security,
color: Colors.purple,
),
hintText: "Your Password",
hintStyle: TextStyle(color: Colors.grey),
suffix: Obx(
() => InkWell(
child: eyeClosed.value
? Icon(Icons.visibility_off, color: Colors.grey)
: Icon(Icons.visibility, color: Colors.purple),
onTap: () {
eyeClosed.value = !eyeClosed.value;
},
),
),
),
),
),
),
),
);
}
}
The suffix icon can be controlled by the Obx(), but the obscureText doesn't work. The direct way is to use Obx() on the TextFormField, but I don't think it is the best way.
Here is the result:
You need to wrap Obx() in TextFormField
Obx(() => TextFormField(...))
Create a controller for your login screen
class LoginController extends GetxController {
RxBool hidePassword = true.obs;
final passwordTextController = TextEditingController();
}
Extends your login screen widget from GetWidget
class LoginScreen extends GetWidget<LoginController> {
final LoginController controller = Get.find<LoginController>();
#override
Widget build(BuildContext context) {
return(); //Define your widget
}
}
Wrap your textfield in Obx(()=> )
Obx(() => FormBuilderTextField(
name: 'password',
controller: controller.passwordTextController,
obscureText: controller.hidePassword.value,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: controller.hidePassword.value ? Icon(Icons.visibility_off)
: Icon(Icons.visibility),
onPressed: () {
controller.hidePassword.value = !controller.hidePassword.value;
},
),
),
),
I have tried with your code & works fine with a little bit change
class LoginPage extends GetView<LoginController>
Also wrap the whole textFormField in Obx(()=>)
i extend a controller for taking values & calling methods in Getx.i can share my full code if you need.
You should use StatefulWidget when your state is changing. Plus, you can reach the same result you want, without "Get" package.
I show you an example here:
import 'package:flutter/material.dart';
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
bool hidePassword = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: TextFormField(
obscureText: hidePassword, // which is true by default
decoration: InputDecoration(
hintText: "Enter Password",
suffixIcon: IconButton(
icon: hidePassword == false
? Icon(
Icons.visibility_rounded,
color: Colors.purple,
)
: Icon(
Icons.visibility_off_rounded,
color: Colors.grey,
),
onPressed: () {
setState(() {
// here we change the value
// if it's false, it gets true
// and if it's true, it gets false
hidePassword = !hidePassword;
});
},
),
),
),
),
),
);
}
}
Related
I want that when I choose home then a text field appears on the screen to input some information.
I wrapped the text field with Visibility but it didn't work.
Container(
margin: const EdgeInsets.only(top: 220,left:0),
child: RadioListTile(
title: const Text('home'),
value: place.home,
groupValue: selacted,
onChanged: (place? value) {
if(place.home==selacted) {
setState(() {
isVisible = true;
selacted= value;
});
}
}
),
),
Container(
margin: const EdgeInsets.only(top: 300,left:0),
child: Visibility(
visible:isVisible,
child:const TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter a search term',
),
),
),
),
It seems you are comparing the previously selected value.
This should work:
setState(() {
_place = value;
_homeFieldVisible = value == Place.home;
});
Full code sample:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
enum Place { road, home, work }
class _HomePageState extends State<HomePage> {
Place? _place;
bool _homeFieldVisible = false;
void handleSelection(Place? value) {
setState(() {
_place = value;
_homeFieldVisible = value == Place.home;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
RadioListTile(
title: const Text('on the road'),
value: Place.road,
groupValue: _place,
onChanged: handleSelection,
),
RadioListTile(
title: const Text('at home'),
value: Place.home,
groupValue: _place,
onChanged: handleSelection,
),
if (_homeFieldVisible)
const TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter a search term',
),
),
RadioListTile(
title: const Text('at work'),
value: Place.work,
groupValue: _place,
onChanged: handleSelection,
),
],
),
),
),
);
}
}
Your onChanged method should be changed to the following.
onChanged: (place? value) {
setState(() {
selacted = value;
if (place.home == selacted) {
isVisible = true;
}
});
}
I am really struggling to understand why my code isn't working. I'm trying to pass the text from two controllers into another widget with named parameters which writes to Firebase.
My "Test" button properly prints both _titleController.text and _descriptionController.text
TextButton(
onPressed: (){
print(_titleController.text); //works fine
print(_descriptionController.text); //works fine
},
child: Text('test')
),
However when I pass these into my next widget it's blank! If I hardcore strings into these parameters it works properly:
PushNewE3 (
changeTitle: _titleController.text, //does not work (empty)
changeDescription: _descriptionController.text, //does not work (empty)
)
Full code:
class CreateE3 extends StatefulWidget {
const CreateE3({Key? key}) : super(key: key);
#override
_CreateE3State createState() => _CreateE3State();
}
class _CreateE3State extends State<CreateE3> {
final _titleController = TextEditingController();
final _descriptionController = TextEditingController();
#override
void initState(){
super.initState();
_titleController.addListener(_printLatestValue);
}
#override
void dispose(){
_titleController.dispose();
super.dispose();
}
void _printLatestValue(){
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('So Frustrating'),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 800,
child: Column(
children: [
Text('Originator: **Add Current User**') ,
TextField(
maxLength: 40,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Change Title'
),
controller: _titleController,
onEditingComplete: (){
//_title = _titleController.text;
},
),
Padding(
padding: const EdgeInsets.fromLTRB(0,10,0,0),
child: TextFormField(
maxLines: 5,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Detailed Description'
),
controller: _descriptionController,
),
),
TextButton(
onPressed: (){
print(_titleController.text); //successfully prints
print(_descriptionController.text); //successfully prints
},
child: Text('test')
),
PushNewE3 (
changeTitle: _titleController.text, //DOES NOT WORK (empty)
changeDescription: _descriptionController.text, //DOES NOT WORK (empty)
)
],
),
),
],
),
);
}
}
class PushNewE3 extends StatelessWidget {
final String changeTitle;
final String changeDescription;
PushNewE3({
required this.changeTitle,
required this.changeDescription
});
#override
Widget build(BuildContext context) {
// Create a CollectionReference called users that references the firestore collection
CollectionReference notificationsE3 = FirebaseFirestore.instance.collection('notificationsE3');
Future<void> pushNewE3() {
// Call the notifications CollectionReference to add a new E3 notification
return notificationsE3
.add({
//'originator': FirebaseAuth.instance.currentUser,
'changeTitle': changeTitle,
'changeDescription': changeDescription,
})
.then((value) => print("E3 Created"))
.catchError((error) => print("Failed to create E3: $error"));
}
return TextButton(
onPressed: (){
print('start:');
print(changeTitle);
print(changeDescription);
print('-end');
},
child: Text(
"Create E3",
),
);
}
}
EDIT:
I still don't understand why the above code doesn't work. I refactored my code into a single widget and now it's working. If anyone can explain why I would still appreciate understanding as there is clearly a gap in my knowledge.
If anyone in the future runs into the same problem here is the refactored code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'main.dart';
var global = 'blank';
class CreateE3 extends StatefulWidget {
const CreateE3({Key? key}) : super(key: key);
#override
_CreateE3State createState() => _CreateE3State();
}
class _CreateE3State extends State<CreateE3> {
final _titleController = TextEditingController();
final _descriptionController = TextEditingController();
#override
Widget build(BuildContext context) {
// Create a CollectionReference called users that references the firestore collection
CollectionReference notificationsE3 = FirebaseFirestore.instance.collection('notificationsE3');
Future<void> pushNewE3() {
// Call the notifications CollectionReference to add a new E3 notification
return notificationsE3
.add({
//'originator': FirebaseAuth.instance.currentUser,
'changeTitle': _titleController.text,
'changeDescription': _descriptionController.text,
})
.then((value) => print("E3 Created"))
.catchError((error) => print("Failed to create E3: $error"));
}
return Scaffold(
appBar: AppBar(
title: Text(_titleController.text),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 800,
child: Column(
children: [
Text('Originator: **Add Current User**') ,
TextField(
maxLength: 40,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Change Title'
),
controller: _titleController,
onChanged: (text){
setState(() {
});
},
),
Padding(
padding: const EdgeInsets.fromLTRB(0,10,0,0),
child: TextFormField(
maxLines: 5,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Detailed Description'
),
controller: _descriptionController,
),
),
TextButton(
onPressed: (){
pushNewE3();
},
child: Text('SAVE')
),
],
),
),
],
),
);
}
}
in the onPressed To pass a value and show it, you have to use setState(() { _myState = newValue; });
Something like this
TextButton(
onPressed: (){
print(_titleController.text);
print(_descriptionController.text);
setState(() { _myNewText = _titleController.text; });
},
child: Text('test')
),
I'm not sure what are you trying to do exactly but here's what I did:
1 - add a local variable _title
2 - add this code to the onPressed function:
setState(() {
_title= _titleController.text;
});
This is the whole code :
class CreateE3 extends StatefulWidget {
const CreateE3({Key? key}) : super(key: key);
#override
_CreateE3State createState() => _CreateE3State();
}
class _CreateE3State extends State<CreateE3> {
final _titleController = TextEditingController();
final _descriptionController = TextEditingController();
String _title = 'So Frustrating';
#override
void initState(){
super.initState();
}
#override
void dispose(){
_titleController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 400,
child: Column(
children: [
Text('Originator: **Add Current User**') ,
TextField(
maxLength: 40,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Change Title'
),
controller: _titleController,
onEditingComplete: (){
//_title = _titleController.text;
},
),
Padding(
padding: const EdgeInsets.fromLTRB(0,10,0,0),
child: TextFormField(
maxLines: 5,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Detailed Description'
),
controller: _descriptionController,
),
),
TextButton(
onPressed: (){
print(_titleController.text);
print(_descriptionController.text);
setState(() {
_title = _titleController.text;
});
},
child: Text('test')
),
],
),
),
],
),
);
}
}
.........................
so this is when you first start the app :
after changing the TextField and pressing the 'test button the title in the appbar change :
I have three pass fields which have icons to show/hide the pass. The default obscureText is true and when the user clicks in the icon, it calls a method _toggle that will turn the obscure text false, showing the textField content.
But, when the user clicks in the icon, it toggles to all the 3 textfields but i wanted toggle only the field clicked. How can I treat this?
My text fields (X 3):
TextFormField(
controller: _controller1,
decoration: _getInputDecoration("Write your current pass"),
keyboardType: TextInputType.text,
obscureText: _isToggle,
My get input decoration (with the icon inside a Gesture detector) :
suffixIcon:
Padding(
padding: EdgeInsetsDirectional.only(end: 12.0),
child: GestureDetector(
child: _isToggle ? Icon(Icons.lock_outline_rounded, color: Colors.black,) :
Icon(Icons.lock_open_rounded, color: Colors.black,),
onTap: _toggle,
)
),
This is the _toggle method:
void _toggle() {
setState(() {
_isToggle = !_isToggle;
});
}
Please check the code for dynamically setting the obscureText when you have multiple TextEditingController.
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> {
List _controller = List<TextEditingController>.generate(
3, (index) => TextEditingController());
List<bool> _isToggle = List<bool>.generate(3, (index) => true);
void _toggle(int index) {
setState(() {
_isToggle[index] = !_isToggle[index];
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Padding(
padding: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
for (int i = 0; i < 3; i++)
TextFormField(
controller: _controller[i],
//decoration: _getInputDecoration("Write your current pass"),
keyboardType: TextInputType.text,
obscureText: _isToggle[i],
decoration: InputDecoration(
suffixIcon: Padding(
padding: EdgeInsetsDirectional.only(end: 12.0),
child: GestureDetector(
child: _isToggle[i]
? Icon(
Icons.lock_outline_rounded,
color: Colors.black,
)
: Icon(
Icons.lock_open_rounded,
color: Colors.black,
),
onTap: () => _toggle(i),
),
),
),
),
],
),
),
),
);
}
}
You need to seperate _isToggle variable for each TextFormField. And set only the tapped TextFormField.
EDIT:
TextEditingController _controller1 = TextEditingController();
TextEditingController _controller2 = TextEditingController();
TextEditingController _controller3 = TextEditingController();
List<bool> toggleList = List<bool>();
void _toggle(int index) {
setState(() {
toggleList[index] = !toggleList[index];
// _isToggle = !_isToggle;
});
}
List<Widget> widgetList = List<Widget>();
InputDecoration _getInputDecoration(String string, int index) {
return InputDecoration(
isDense: true,
suffixIcon: Padding(
padding: EdgeInsetsDirectional.only(end: 12.0),
child: GestureDetector(
child: toggleList[index]
? Icon(
Icons.lock_outline_rounded,
color: Colors.black,
)
: Icon(
Icons.lock_open_rounded,
color: Colors.black,
),
onTap: () {
_toggle(index);
},
),
),
);
}
addList() {
widgetList.add(TextFormField(
controller: _controller1,
decoration: _getInputDecoration("Write your current pass", 0),
keyboardType: TextInputType.text,
obscureText: toggleList[0],
));
widgetList.add(TextFormField(
controller: _controller2,
decoration: _getInputDecoration("Write your current pass", 1),
keyboardType: TextInputType.text,
obscureText: toggleList[1],
));
widgetList.add(TextFormField(
controller: _controller3,
decoration: _getInputDecoration("Write your current pass", 2),
keyboardType: TextInputType.text,
obscureText: toggleList[2],
));
}
#override
Widget build(BuildContext context) {
return ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: widgetList.length,
itemBuilder: (BuildContext context, int index) {
return widgetList[index];
});
It is because you're using a single variable(_isToggle) for all the fields.
Using 3 separate booleans would solve the problem.
bool _isToggle1=false;
bool _isToggle2=false;
bool _isToggle3=false;
suffixIcon:
Padding(
padding: EdgeInsetsDirectional.only(end: 12.0),
child: GestureDetector(
child: _isToggle1 ? Icon(Icons.lock_outline_rounded, color: Colors.black,) :
Icon(Icons.lock_open_rounded, color: Colors.black,),
onTap: ()=>setState(()=>_isToggle1=!_isToggle1),
)
),
i have textformfield i want to get access to what it shows
like when i print 10000 i want it to show and separate the int like 10,000 , i can print it with regex but i want to show it in text form field too
here us what i got in terminal (left) and what it shows in text field (right)
enter image description here
and all i wanna do is show what is in terminal to text field\
.
if you need more information please let me know
here is my code
import 'package:flutter/material.dart';
class AddTransication extends StatefulWidget {
#override
_AddTransicationState createState() => _AddTransicationState();
}
class _AddTransicationState extends State<AddTransication> {
RegExp reg_ex = new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))');
Function mathFunc = (Match match) => '${match[1]},';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Test Screen"),
actions: <Widget>[
FlatButton(
textColor: Colors.white,
onPressed: () {},
child: Text("Save"),
shape: CircleBorder(side: BorderSide(color: Colors.transparent)),
),
],
),
body: SafeArea(
child: Form(
child: Column(
children: [emailField(reg_ex, mathFunc)],
),
),
),
);
}
Widget emailField(reg_ex, mathFunc) {
return TextFormField(
onChanged: (str) {
String result = str.replaceAllMapped(reg_ex, mathFunc);
print(' $result');
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email Address',
hintText: 'you#example.com',
),
);
}
}
You have to use TextEditingController class.
A controller for an editable text field.
Whenever the user modifies a text field with an associated TextEditingController, the text field updates value and the controller notifies its listeners. Listeners can then read the text and selection properties to learn what the user has typed or how the selection has been updated.
Refer : https://api.flutter.dev/flutter/widgets/TextEditingController-class.html
Please check the code, below I have updated it to work as per your question.
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: AddTransication(),
);
}
}
class AddTransication extends StatefulWidget {
#override
_AddTransicationState createState() => _AddTransicationState();
}
class _AddTransicationState extends State<AddTransication> {
final _controller = TextEditingController();
RegExp regex = new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))');
Function mathFunc = (Match match) => '${match[1]},';
void initState() {
super.initState();
}
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Test Screen"),
actions: <Widget>[
FlatButton(
textColor: Colors.white,
onPressed: () {},
child: Text("Save"),
shape: CircleBorder(side: BorderSide(color: Colors.transparent)),
),
],
),
body: SafeArea(
child: Form(
child: Column(
children: [emailField(regex, mathFunc)],
),
),
),
);
}
Widget emailField(regex, mathFunc) {
return TextFormField(
controller: _controller,
onChanged: (str) {
String text = str.replaceAll(",", "").replaceAllMapped(regex, mathFunc);
print(' $text');
_controller.value = _controller.value.copyWith(
text: text,
selection:
TextSelection(baseOffset: text.length, extentOffset: text.length),
composing: TextRange.empty,
);
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email Address',
hintText: 'you#example.com',
),
);
}
}
I'm experimenting with Flutter development on Windows. I have a simple test app with an InputField. I would like the first keyboard entry to be a capital letter but can't see a way of achieving that (e.g. launching the keyboard with shift pressed) that at the moment. Any ideas?
Code (a bit simplified) is:
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
theme: new ThemeData.dark(),
home: new MainScreen()
));
}
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
leading: new IconButton(
icon: new Icon(Icons.menu),
tooltip: 'Navigation menu',
onPressed: null,
),
title: new Text('Test'),
),
body: new NewTest(),
);
}
}
/// Widget
class NewTest extends StatefulWidget {
#override
_NewTestInputState createState() => new _NewTestInputState();
}
/// State
class _NewTestInputState extends State<NewTest> {
InputValue _currentInput;
void _handleInputChange(InputValue input) {
if (input != _currentInput){
setState(() {
_currentInput = input;
});
}
}
void _handleInputSubmitted(InputValue input) {
setState(() {
_currentInput = const InputValue();
});
}
#override
Widget build(BuildContext context) {
InputField _widget = new InputField(
value: _currentInput,
hintText: 'Enter text',
keyboardType: TextInputType.text,
autofocus: true,
onChanged: _handleInputChange,
onSubmitted: _handleInputSubmitted,
style: new TextStyle(fontSize: 20.0),
);
Container _container = new Container(
child: _widget,
decoration: new BoxDecoration(
border: new Border.all(
color: Colors.green[300],
width: 2.0,
),
),
padding: new EdgeInsets.all(16.0),
);
return _container;
}
}
Flutter has a textCapitalization property for textfields. Set this property to TextCapitalization.sentences or any of the available values eg .characters or .words Like so:
TextField(
keyboardType: TextInputType.text,
**textCapitalization: TextCapitalization.sentences,**
style: TextStyle(
fontSize: 30.0,
color: Colors.black,
fontWeight: FontWeight.bold
),
)
The starting-lowercase was a bug in our iOS implementation of Flutter's keyboard wrapper, which has since been fixed as of today!
I filed a bug for making this configurable (so you can disable the autocapitalize sentences behavior) here: https://github.com/flutter/flutter/issues/9363
Please don't hesitate to reach out if this does not resolve your issue.