How can I limit the size of a text field in flutter? - textfield

The TextField widget doesn't seem to have a "limit" attribute to limit the number of characters that can be typed. How I can enforce that only a certain number of characters can be provided as input in a TextField Widget. I tried looking at the decoration property and potentially setting the limit there somehow but that didn't seem to work either. Is there a different widget I should be using?

Use inputFormatters property
example:
TextFormField(
inputFormatters: [
LengthLimitingTextInputFormatter(10),
]
)
namespace
import 'package:flutter/services.dart';

You can use the maxLength property and you can still hide the bottom counter text by setting the counterText to empty string.
TextField(
maxLength: 10,
decoration: InputDecoration(
counterText: ''
),
)

maxLength property is available in Flutter.
https://docs.flutter.io/flutter/material/TextField/maxLength.html
TextField(
maxLength: 45,
)

I had to add an additional snippet to what RSproute mentioned. The full code is here:
TextEditingController _controller = new TextEditingController();
String text = ""; // empty string to carry what was there before it
onChanged
int maxLength = ...
...
new TextField(
controller: _controller,
onChange: (String newVal) {
if(newVal.length <= maxLength){
text = newVal;
}else{
_controller.value = new TextEditingValue(
text: text,
selection: new TextSelection(
baseOffset: maxLength,
extentOffset: maxLength,
affinity: TextAffinity.downstream,
isDirectional: false
),
composing: new TextRange(
start: 0, end: maxLength
)
);
_controller.text = text;
}
}
);

You can control everything about the Text Field with the TextEditingController. So if you were to pair this information with an onChanged event from the TextField you could perform any logic you like in there. For example:
TextEditingController _controller = new TextEditingController();
String text = ""; // empty string to carry what was there before it onChanged
int maxLength = ...
...
new TextField(
controller: _controller,
onChanged: (String newVal) {
if(newVal.length <= maxLength){
text = newVal;
}else{
_controller.text = text;
}
}
)
I am able to control the text field to stay within the guidelines because if it ever goes over it, it will revert to what it was before the last type.

With th version 1.25 this is even easier. The maxLengthEnforced property needs to be set to true. Otherwise the response above will not work.
Container(
margin: EdgeInsets.only(right: 5),
child: SizedBox(
width: 70,
child: TextField(
keyboardType: TextInputType.number,
maxLengthEnforced: true,
maxLength: 2,
decoration: InputDecoration(
labelText: 'Hours',
counterText: '',
),
controller: hourField,
),
),
),

You can set LengthLimitingTextInputFormatter in input formatters
TextField(
keyboardType: TextInputType.number,
inputFormatters: [
LengthLimitingTextInputFormatter(n,), //n is maximum number of characters you want in textfield
],
),

There are two ways to do that
Solution One
LengthLimitingTextInputFormatter Creates a formatter that prevents the insertion of more characters than a limit.
TextField(
inputFormatters: [
new LengthLimitingTextInputFormatter(5), /// here char limit is 5
],
///....
)
Solution Two:
TextField(
maxLength: 5, /// here char limit is 5
If you don't want to show counter text at TextField bottom then add empty counterText in InputDecoration
Example:
TextField(
maxLength: 100,
decoration: InputDecoration(
counterText: '',
///....

You can use this code snipped to limit length and hide counter:
TextFormField(
maxLength: 10,
buildCounter: (BuildContext context, { int currentLength, int maxLength, bool isFocused }) => null,
);
Original answer you can find here.

Related

How to put json-data into a list in flutter?

When I try to get data from this API https://api.met.no/weatherapi/locationforecast/2.0/complete?lat=10&lon=10 it gets me a long array of some sort with all the timeseries. In the end, I would like to display some data from each time which has its own place in the downloaded array. I want to covert all data to a list so I can manipulate the data but i get errors like these type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String.
This is my code
List<dynamic> timeseriesglobal = [];
void loadForecast() async{
//Getting the data from API
Response response = await get("https://api.met.no/weatherapi/locationforecast/2.0/complete?lat=57.047218&lon=9.920100");
var results = jsonDecode(response.body);
timeseriesglobal = results["properties"]["timeseries"] as List;
}
And in the end i have this code for displaying the data
child: ListView.builder(
itemCount: timeseriesglobal.length,
itemBuilder: (context,index){
return Card(
child: ListTile(
title: Text(
timeseriesglobal[index]
),
),
);
},
What am I doing wrong? Please help me
Provide the property name that you want to show Ex time
ListView.builder(
itemCount: timeseriesglobal.length,
itemBuilder: (context,index){
return Card(
child: ListTile(
title: Text(
timeseriesglobal[index]['time']
),
),
);
},
Create Your BaseModel from the json you are getting from the link.
Then Parse like below
var data= BaseModel.fromJson(response.body);
Now this will contain everything and you can extract whatever u want from the model
To convert the json use this link

Use textfield input to get a value output

I have made a simple textfield with a number keyboard.
The user is to put in a number (to make it simple I have set the number to sum=5).
If input is = sum, the text 'correct answer' will be printed on the screen. If the user input !=sum, the returned text will be 'wrong answer'.
To test if I actually got the numbers right I have a testprint, which functions correct.
My problem is how to transform this print output to text (so that it will show as text in the app).
I have been thinking about validating and form, but since I actually already get the correct answer printed, it shows I already get the values correct. Right?
I have tried a ton of things, but nothing has worked so far, so any help is appreciated. Thank you.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Textfields2',
home: MyHomeScreen(),
);
}
}
class MyHomeScreen extends StatefulWidget {
#override
_MyHomeScreenState createState() => _MyHomeScreenState();
}
class _MyHomeScreenState extends State<MyHomeScreen> {
final int sum = 5;
String output;
String enterAnswer;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: '?'),
onChanged: (val) {
enterAnswer = val;
},
),
RaisedButton(
child: Text('Submit Answer'),
onPressed: () {
if (enterAnswer.isNotEmpty) {
if (enterAnswer == sum.toString()) {
print('Correct'); //INTO TEXT
} else {
print('Wrong Answer');//INTO TEXT
}
}
})
],
),
),
);
}
}
Below the RaisedButton add a Text Widget. It should look something like this:
Text(output)
, then replace the print() statement with a setState() function updating the output:
setState(() {output = 'Correct';});
To not get an error in the first place you have to initialize the output variable, so instead of only writing
String output;
write
String output = "";

Flutter - Creating tables dynamically

I'm trying to dynamically create tables using Dart and Flutter. Something like this The number of table rows will change depending on the the JSON file passed in.
I've read through and done all of the Flutter tutorials I can get my hands on and read through the Documentation on the Table and ListBuilder classes, but none of them quite accomplish what I'm trying to do, because the examples either only dynamically create single ListItems or all the data and/or Widgets are hard-coded.
I've also tried doing this by doing:
Table dynamicTable = new Table(); then dynamically adding children Widgets with
dynamicTable.add(TableRow(
children: [
Text("test1"),
Text("test2"),
Text("test3"),
]
));
But I get an error saying "Cannot add to an unmodifiable list".
Any tips on how to accomplish this would be greatly appreciated.
This function creates a table dynamically:
Widget createTable() {
List<TableRow> rows = [];
for (int i = 0; i < 100; ++i) {
rows.add(TableRow(children: [
Text("number " + i.toString()),
Text("squared " + (i * i).toString()),
]));
}
return Table(children: rows);
}
First fetch List of Records
List<PriceDetailsView> priceDetailsList = MockDataSource.getPriceDetailsDataList();
Now create an empty list of table rows :
List<TableRow> priceTableRows = [];
Add details from the fetched list to this row list:
for(PriceDetailsView priceDetalis in priceDetailsList){
priceTableRows.add(TableRow(children: [Text(priceDetalis.priceType), Text(priceDetalis.priceValue)]));
}
Now create your table with this list of row :
Table priceTable = Table(children: priceTableRows);
Suppose you have this model class:
class Person {
final int id;
final String name;
final String email;
final String phone;
const Person({
this.id = 0,
this.name = '',
this.email = '',
this.phone = '',
});
...
}
and you have populated a List of Person with data from an API call:
List<Person> _personList = ...
To generate the TableRow, you can do it using List.generate Dart function:
return Table(
border: TableBorder.all(color: Colors.black),
children: List<TableRow>.generate(
_personList.length,
(index) {
final person = _personList[index];
return TableRow(
children: [
Padding(
padding: EdgeInsets.all(5.0),
child: Text(person.id.toString(), textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(5.0),
child: Text(person.name, textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(5.0),
child: Text(person.email, textAlign: TextAlign.center),
),
Padding(
padding: EdgeInsets.all(5.0),
child: Text(person.phone, textAlign: TextAlign.center),
),
],
);
},
growable: false,
),
);
It's pretty easy, actually! All you have to do is, make a list of TableRows, and put that in the children parameter of your table. For example
List<TableRow> tableRows = [];
// dynamically make TableRows and add them to the list
And then you can just do this:
Table(
children: tableRows,
// other stuff
)

How to add a Password input type in flutter makes the password user input is not visible , just like Android Native EditText 's inputtype:password?

i meet a problem that Flutter 's TextInputType do not have a password type:
/// All possible enum values.
static const List<TextInputType> values = const <TextInputType>[
text, multiline, number, phone, datetime, emailAddress, url,
];
how to make the password user input not visible? any one has a good idea ?
In case you are using the TextField widget (or something that derives from this widget), you can use the obscureText property and set it to true. More details can be found here.
Additionally, consider adding these properties to prevent input suggestions because they risk revealing at least part of the password input to screen viewers.
obscureText: true,
enableSuggestions: false,
autocorrect: false,
Just add obscureText: true in TextFormField:
TextFormField(
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
),
validator: (String value) {
if (value.trim().isEmpty) {
return 'Password is required';
}
return null;
},
),
There are only two places where we can hide the password.
1. Using TextFormField
TextFormField(
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
),
),
2. Using TextField
TextField(
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
),
)
Using TextField
obscuringCharacter: "*",
TextField(
obscureText: true,
onChanged: (){},
obscuringCharacter: "*",
decoration: InputDecoration(
hintText: "Enter password",
icon: Icon(Icons.lock,color: kPrimaryColor,),
),
),

Strange red Block under Flutter TextField Widget

I'm working on a shopping list in one tab of my flutter app but under the Input field i always get and strange red block when the keyboard comes up (red block stays there until keyboard goes away)
RedBlock which appears with keyboard
Debug report which shows up after clicking into the field
Performing full restart...
Restarted app in 1.172ms.
D/ViewRootImpl#da3a8cd[MainActivity](28869): ViewPostImeInputStageprocessPointer 0
D/ViewRootImpl#da3a8cd[MainActivity](28869): ViewPostImeInputStageprocessPointer 1
I/flutter (28869): [{name: Lukas, id: 1, value: 32}, {name: Sophie, id: 2, value: 20}, {name: Peter, id: 3, value: 45}]
D/ViewRootImpl#da3a8cd[MainActivity](28869): ViewPostImeInputStage processPointer 0
D/ViewRootImpl#da3a8cd[MainActivity](28869): ViewPostImeInputStage processPointer 1
V/InputMethodManager(28869): Starting input: tba=android.view.inputmethod.EditorInfo#b63ece2 nm : com.yourcompany.flutterapp ic=io.flutter.plugin.editing.InputConnectionAdaptor#484e873
I/InputMethodManager(28869): [IMM] startInputInner - mService.startInputOrWindowGainedFocus
D/InputTransport(28869): Input channel constructed: fd=101
D/InputTransport(28869): Input channel destroyed: fd=100
D/InputMethodManager(28869): ISS - flag : 0Pid : 28869 view : com.yourcompany.flutterapp
D/ViewRootImpl#da3a8cd[MainActivity](28869): MSG_RESIZED: frame=Rect(0, 0 - 1080, 2220) ci=Rect(0, 63 - 0, 918) vi=Rect(0, 63 - 0, 918) or=1
D/ViewRootImpl#da3a8cd[MainActivity](28869): Relayout returned: oldFrame=[0,0][1080,2220] newFrame=[0,0][1080,2220] result=0x1 surface={isValid=true -887126016} surfaceGenerationChanged=false
Here you can see my code i have written:
import 'dart:async';
import 'dart:core';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class ShoppingBasket extends StatefulWidget {
#override
ShoppingBasketState createState() => new ShoppingBasketState();
}
class ShoppingBasketState extends State<ShoppingBasket> {
Directory documentsDirectory;
String dirPath;
Database database;
List<Map> listRecords;
Widget listView;
final TextEditingController _controller1 = new TextEditingController(); // name field
final TextEditingController _controller2 = new TextEditingController(); // value field
#override
void initState() {
listView = beforeDataFetchIsFinished();
getPathAndCheckForDbAndPrepareListView();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Column(
children: <Widget>[
inputFieldCard(),
listView, //--> List view gets after all data was fetched here
],
),
);
}
//-----------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------
//View Build ------------------------------------------------------------------------
/// Set the listview variable with an CircularPorgressIndicator.
/// gets overriden if the real listview has finished.
Widget beforeDataFetchIsFinished() {
return new Container(
margin: new EdgeInsets.fromLTRB(0.0, 30.0, 0.0, 0.0),
child: new Center(
child: new CircularProgressIndicator(
strokeWidth: 2.0,
),
),
);
}
/// The Inputfield card in one methode.
/// Returns the InputCard as one widget.
Widget inputFieldCard() {
return new Container(
child: new Card(
child: new Container(
child: new Column(
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Container(
width: 150.0,
padding: new EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 10.0),
child: new TextField(
controller: _controller1,
decoration: new InputDecoration(
hintText: 'Name...',
),
),
),
new Container(
width: 150.0,
padding: new EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 10.0),
child: new TextField(
keyboardType: TextInputType.number,
controller: _controller2,
decoration: new InputDecoration(
hintText: 'Value...',
),
),
),
],
),
new Container(
padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 20.0),
child: new RaisedButton(
color: Colors.green,
child: new Text('Insert Data', style: new TextStyle(color: Colors.white),),
onPressed: () {
insertToDb(_controller1.text, _controller2.text);
_controller1.clear();
_controller2.clear();
},
),
),
],
)
),
), //top card end
);
}
/// the CircularProgressIndicator gets overiden if this
/// methode gets all its data --> then rerender.
Widget injectListViewAfterAllDataIsFetched() {
return new Card(
child: new Container(
child: new ListView.builder(
shrinkWrap: true, //<-- Necessary because Listveiw inside Column
itemCount: listRecords == null ? 0 : listRecords.length,
itemBuilder: (BuildContext context, int index) {
return new ListTile(
title: new Text(listRecords[index]['name']),
);
},
),
),
);
}
//-----------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------
//Data-Base Operations --------------------------------------------------------------
/// Start up --> Open db and fetching data when complete
/// start render engine again.
Future<bool> getPathAndCheckForDbAndPrepareListView() async {
documentsDirectory = await getApplicationDocumentsDirectory();
String dirPath = documentsDirectory.path;
List content = documentsDirectory.listSync();
final File file = new File(dirPath + '/myDataBase.db');
if(!content.contains(file)) { //Check if db exists
await createDbIfNotExists(file); //if not create it
}
print(await getRecords());
listRecords = await getRecords();
print(listRecords);
setState(() {
listView = injectListViewAfterAllDataIsFetched();
});
return true;
}
/// Inserting data into the data base.
/// #return true.
Future<bool> insertToDb(String name, String value) async {
if(name != '' && value != '') {
var valueSql = int.parse(value);
String sql = 'INSERT INTO Test(name, value) VALUES("$name", $valueSql)';
await database.inTransaction(() async {
await database.rawInsert(sql);
});
listRecords = await getRecords();
setState(() {
listView = injectListViewAfterAllDataIsFetched();
});
return true;
} else {
return false;
}
}
/// Gives the whole Db back.
/// #return Map with all records.
Future<List<Map>> getRecords() async {
return await database.rawQuery('SELECT * FROM Test');
}
/// Creating the given File (should be an .db file).
/// #param file Gives the file (.db) which gets created.
/// #return true.
Future<bool> createDbIfNotExists(File file) async {
database = await openDatabase(file.path, version: 1,
onCreate: (Database db, int version) async {
await db.execute(
"CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER)");
});
return true;
}
}
Does someone of you understand why this is showing up? And have an smart Solution to fix it?
Edit: Some Photos which show my Keyboard with shortcuts and without them
I was facing the same problem. Just set resizeToAvoidBottomPadding false in you scaffold and it should solve the problem.
The red bar indicates that the content of one of your containers or columns are bigger, than allowed by their parent. I cant reproduce this issue on iOS or Android. Also, why is the raised button not displayed in your screenshot?