Flutter: TextField auto add a dot when input multiple spaces - flutter

I just implement a simple TextField, but when I input multiple spaces, it auto add a dot before that.
my-custom-flutter-textfield
Here is my custom TextField widget
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(5),
child: Column(children: [
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Text(
title,
),
)),
TextField(
controller: _controller,
autocorrect: false,
decoration: InputDecoration(
isDense: true,
contentPadding: const EdgeInsets.all(10),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: Colors.black,
width: 2,
),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: Colors.orange,
width: 2,
),
borderRadius: BorderRadius.circular(5),
),
))
]));
}

This is a standard function of the iOS keyboard and most Android keyboards. I don't think you can control that from Flutter.

I don't think that has anything to do with the app itself, but the phone. You'd need to disable that from the phone's settings.
Although, if you really need to be able to type double spaces, here is how I'd implement it.
final TextEditingController controller = TextEditingController();
TextSelection? cursor;
int length = 0;
String lastChar = '';
String currentChar = '';
String replaceCharAt(String oldString, int index, String newChar) {
// function from https://stackoverflow.com/questions/52083836/how-to-replace-only-one-character-in-a-string-in-dart
return oldString.substring(0, index) +
newChar +
oldString.substring(index + 1);
}
void removeDotOnSpace(String input) {
//save the position of the cursor
cursor = controller.selection;
lastChar = currentChar;
// if the input isn't empty and if you're not removing text
if (input.isNotEmpty && input.length > length) {
currentChar = input[input.length - 1];
// if it has at least two characters, the second to last being a dot and the "lastChar" variable not being a dot
if (input.length >= 2 &&
input[input.length - 2] == '.' &&
lastChar != '.') {
// replace the dot and set state. Because setstate resests cursor position we need to save it and give it back.
setState(() {
controller.text = replaceCharAt(input, input.length - 2, ' ');
controller.selection = cursor!;
});
}
} else {
currentChar = '';
lastChar = '';
}
length = input.length;
}
Put this inside a stateful widget and use it inside the onchanged function
TextFormField(
controller: controller,
onChanged: (value) {
removeDotOnSpace(value);
},
),
PS: Unless it's essential for your textfields to be able to have double spaces, you should just let it be.

try textCapitalization: TextCapitalization.words,

put this function onBlur in form inputs:
const handleTrimDataAndRemoveDot = () => {
const trimmedData = formData.trim();
let validatedData;
if (trimmedData.charAt(trimmedData.length - 1) === ".") {
validatedData = trimmedData.replace(
trimmedData.charAt(trimmedData.length - 1),
""
);
} else {
validatedData = trimmedData;
}
setFormData(validatedData);
};

Related

TRYING TO GET interger from TexteditingController to build a M

i want to make a dodging (Multiplication) Table...and wanna take input from user from TexteditingController, but i am not able to take the integer value from the Text Editing controller. looking forward if someone would look into it,
TextEditingController num = TextEditingController();
void table() {
print('enter the number $num');
for (var i = 1; i <= 10; i++) {
print('$num*$i = ${num * i}'); //<error>(The operator '*' isn't defined for the type,,'')
}
}
Scaffold(
body: Column(
children: [
TextFormField(
controller: TextEditingController(),
),
Container(
height: 400,
width: 400,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(20),
),
child: ElevatedButton(
onPressed: table,
child: Text('')),
),
],
));
}
}
The error comes from the fact that you access the TextEditingController directly instead of grabbing the text it contains.
Correct would be:
TextEditingController controller = TextEditingController();
void table() {
var enteredText = controller.text;
var enteredNumber = int.parse(enteredText)
for (var i = 1; i <= 10; i++) {
print('$enteredNumber*$i = ${enteredNumber * i}');
}
}

How to set Visibility function in flutter to show or hide Text Form Field?

I want to set an option in my Trivia game to the user set a Text Field in specific question ID.
for now I trying to use Visibility widget but its only take the bool _visibleText value,
And does not get the value from void validateText.
any idea what I missing?
this is my code:
class _QuestionCardState extends State<QuestionCard> {
bool _visibleText = false;
void validateText() => setState(() {
if (widget.question.id == 1) {
_visibleText = false;
} else {
if (widget.question.id == 2) {
_visibleText = true;
}
}
});
and the widget:
Visibility(
visible: (_visibleText),
child: Container(
width: 320.0,
alignment: Alignment.center,
child: TextFormField(
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: const OutlineInputBorder(
borderSide:
const BorderSide(color: Color(0xFFCBA583), width: 2.0),
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
filled: true,
fillColor: Colors.white,
hintText: widget.question.text,
hintStyle: TextStyle(
fontSize: 16.0,
color: Color(0xFF067751),
fontFamily: 'Calibri',
letterSpacing: 2,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
),
),
),
Solved by using this function:
bool validateText() {
if (widget.question.id == 2) {
return true;
}
return false;
}
If you need to continuously toggle visibility during the game, please use streambuilder and leave your validatetext function inside streambuilder's sink method. Then streamcontroller will continuously change your UI dynamically.
If you don't understand at all, then please mention that , I will try to add the full codebase.
Thank You.
validateText is never called.
Change the function to this :
bool validateText() {
if (widget.question.id == 1) return false;
if (widget.question.id == 2) return true;
}
And in your build method :
visible: validateText(),
The validateText function is never called. If you have a button that toggles this then call it in it's onTap event.

I can't change the hinttext in the dropdownButton

This is my code, and i dont know why the hint doesnt change, when i click the options, obviously all this code is inside a class, I tried to use a for loop to identify the list positions , and if they were right, it would appear on the screen.
final listgenre = ["Masc", "Fem", "Não Binário"];
var listgenre_value;
String newValue = "";
var valueChoose;
String hintValue = "";
Padding(
padding: EdgeInsets.all(16),
child: Container(
padding: EdgeInsets.only(left: 16, top: 10, right: 15),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
borderRadius: BorderRadius.circular(20)),
child: DropdownButton<String>(
hint: Text("Genero :$hintValue"),
dropdownColor: Colors.white,
icon: Icon(Icons.arrow_drop_down),
iconSize: 36,
iconEnabledColor: Colors.black,
isExpanded: true,
style: TextStyle(fontSize: 17, color: Colors.black),
value: valueChoose,
underline: SizedBox(
width: 320,
height: 200,
),
items: listgenre.map((valueitem) {
return DropdownMenuItem(
value: valueitem,
child: Text(valueitem),
);
}).toList(),
onChanged: (newValue) {
setState(() {
for (int i = 0; i <= listgenre.length; i++) {
if (listgenre[i] != newValue) {
listgenre_value = i + 1;
} else {
hintValue = "$newValue";
// ignore: void_checks
return listgenre_value;
}
}
Object? valueChoose = newValue;
String valueChoosen = valueChoose.toString();
});
},
))),
As per your comments, the same code doesn't give the expected output.
It is only possible if you are also initialising the variables inside the build method, which shouldn't be the case.
Incorrect Code
#override
Widget build(BuildContext context) {
// ---- your variables INSIDE build method
final listgenre = ["Masc", "Fem", "Não Binário"];
var listgenre_value;
String newValue = "";
var valueChoose;
String hintValue = "";
// ------- rest of the code continued
Correct Code
final listgenre = ["Masc", "Fem", "Não Binário"];
var listgenre_value;
String newValue = "";
var valueChoose;
String hintValue = "";
#override
Widget build(BuildContext context) {
// ------- rest of the code continued
As the build method is called every time setState is called, hintValue was being initialised to "" i.e empty string.
The correct way to fix this error is abdev's comment. It will help if you put the variables used by the DropdownButton widget above the build method.
I hope it was helpful!

Resetting TextfieldController for all textfields, using provider

I'm having a problem trying to figuring out the proper way on how to do this. Basically in my app, I want to reset all the fields for "cleanup" by the user. I can reset everything, but the TextFields. The only way that I found to solve the problem is by using the if that you can see inside the Consumer. I don't think though it's the proper way on how to handle this type of thing.
I also thought to push inside my provider class all the controller and then reset them, but I think it's still too heavy. I'm trying to find the cleanest and lightest solution, even to learn what's the best practice in these situations.
Thanks in advance!
return Provider.of<Provider_Class>(context, listen: false).fields[_label] != null ? SizedBox(
height: 57.5,
child: Consumer<Provider_Class>(builder: (context, provider, child) {
if (provider.resetted == true) {
_controller.text = "";
}
return Material(
elevation: this.elev,
shadowColor: Colors.black,
borderRadius: new BorderRadius.circular(15),
animationDuration: new Duration(milliseconds: 500),
child: new TextField(
focusNode: _focusNode,
keyboardAppearance: Brightness.light,
style: Theme.of(context).textTheme.headline5,
controller: _controller,
keyboardType: TextInputType.number,
textAlign: TextAlign.end,
inputFormatters: <TextInputFormatter>[
LengthLimitingTextInputFormatter(8),
_whichLabel(widget.label),
],
decoration: new InputDecoration(
enabledBorder: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(15),
borderSide: new BorderSide(width: 1.2, color: CliniLiliac300),
),
focusedBorder: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(15),
borderSide: new BorderSide(width: 2.5, color: CliniLiliac300),
),
filled: true,
fillColor: Colors.white,
hintText: "0.0",
hintStyle: new TextStyle(fontSize: 15, color: Colors.black, fontFamily: "Montserrat"),
),
onChanged: (val) {
var cursorPos = _controller.selection;
val = val.replaceAll(",", ".");
if (val == "") {
provider.fields[_label] = 0.0;
} else if (double.parse(val) > provider.measure[_label] &&
provider.measure[_label] != 0) {
provider.fields[_label] % 1 == 0
? _controller.text = provider.fields[_label].toString().split(".")[0]
: _controller.text = provider.fields[_label].toString();
if (cursorPos.start > _controller.text.length) {
cursorPos = new TextSelection.fromPosition(
new TextPosition(offset: _controller.text.length),
);
}
_controller.selection = cursorPos;
} else {
provider.fields[_label] = double.parse(val);
}
provider.calculateResultRA();
},
),
);
}),
) : SizedBox();
}
Use TextFormField instead of TextField. TextFormField has several callbacks like validator, onSaved, onChanged, onEditingComplete, onSubmitted, ...
You can connect all your TextFormFields by wrapping it in a Form. This form should be given a GlobalKey so that you can identify the Form and call methods on FormState.
final _form = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
// ...
return Form(
key: _form,
child: // build Material with TextFormFields
);
}
Now to call onSaved on each TextFormField, you can call _form.currentState().save(). To reset every TextFormField you can call _form.currentState().reset().
You can get more information about how to build a Form and the functions you can call on FomState here:
https://flutter.dev/docs/cookbook/forms/validation
https://api.flutter.dev/flutter/widgets/FormState-class.html

TextField keeps old value

I have an issue with a textfield in flutter.
I need to get a town or postal code to redirect the user to another page. But it seems like I keep old value even if the text inside textfield changes.
I tried to clear it, make conditions but I don't understand why the text does not keep the current value.
Here some code :
Check if it's Paris, for the borough
#override
void initState() {
editingController.addListener((){
setState(() {
if(editingController.text.isEmpty) {
editingController.clear();
isParis = false;
}
});
});
super.initState();
}
Button which redirect, the method getPcFromQuery (it's an async method) retrieve data relatives to a town name.
RaisedButton(
onPressed: (){
print(editingController.text);
getPCFromQuery(editingController.text)
.then((town) {city = town.featureName; postalCode = town.postalCode;});
setState(() {
if(city.toString().toLowerCase() == "paris")
isParis = true;
else
isParis = false;
});
print("postalCode : $postalCode");
postalCode != null && city.toString().toLowerCase() != "paris"?
Navigator.of(context).push(MaterialPageRoute(builder: (context) => PreferencesPage(postalCode: postalCode))) :
Container(child: Text(""));
})
But when I click on the next button (I need to click on it two times to make it work) and when I change the value inside my textfield, it keeps the previously entered value.
Do you know where it can come from?
This is TextField built:
class SearchBar extends StatelessWidget {
const SearchBar({
Key key,
#required this.editingController,
}) : super(key: key) ;
final TextEditingController editingController;
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(10.0)),
child: TextField(
controller: editingController,
decoration: InputDecoration(
hintText: AppStrings.searchTown,
hintStyle: GoogleFonts.notoSans(fontSize: 14.0),
border: InputBorder.none,
fillColor: Colors.grey.withOpacity(0.5),
prefixIcon: Icon(Icons.search, color: Colors.grey)
),
)
);
}
}
And method _getPcFromQuery :
_getPCFromQuery(String city) async {
var addresses = await Geocoder.local.findAddressesFromQuery(city);
var first = addresses.first;
print(first.featureName);
print(first.addressLine);
return first;
}
The weird thing is, when I try the first time, the prints inside _getPcFromQuery method get text, but the print "print("postalCode : $postalCode");" on the onPressed method button is null.
Specify the key parameter for TextField.
class SearchBar extends StatelessWidget {
const SearchBar({
Key key,
#required this.editingController,
}) : super(key: key) ;
final TextEditingController editingController;
final searchKey = GlobalKey(); // <-- create a global key
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(10.0)),
child: TextField(
key: searchKey, // <-- specify the declared key here
controller: editingController,
decoration: InputDecoration(
hintText: AppStrings.searchTown,
hintStyle: GoogleFonts.notoSans(fontSize: 14.0),
border: InputBorder.none,
fillColor: Colors.grey.withOpacity(0.5),
prefixIcon: Icon(Icons.search, color: Colors.grey)
),
)
);
}
}