I'm new to flutter, I am Trying to create Count Number of Lines from textfield, like this https://www.tools4noobs.com/online_tools/count_lines/. but, I still have a problem with how to calculate it.
Can you give an example, I will appreciate it.
So what I have found to get number of lines from a text is this flutter-how-to-get-the-number-of-text-lines
To read text you can use this Handling changes to a text field
Here's an example I did using onChanged function.. You can use a controller also
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
num lines = 0;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: <Widget>[
TextField(
maxLines: null,
onChanged: (text) {
setState(() {
lines = '\n'.allMatches(text).length + 1;
});
},
),
Text(lines.toString())
],
)),
);
}
}
Related
Lets assume a class "SpecialButton" and its State-Class "SpecialButtonState"
class SpecialButton extends StatefulWidget {
bool active = false;
SpecialButton({Key key}) : super(key: key);
#override
SpecialButtonState createState() => SpecialButtonState();
}
class SpecialButtonState extends State<SpecialButton> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
decoration:
BoxDecoration(color: this.widget.active ? COLOR_1 : COLOR_2),
child: null);
}
}
In the parent widget, I manage a couple of these buttons. Therefore, I want to assign a state to them. The solution I tried was to introduce a flag "active" in the SpecialButton class which I can easily set to either true or false from the parent widget. I can then use this in the build function of the state class to colorize the button. Unfortunately, this does not work completely as it does not update the button immediately (it needs some kind of state update e.g. by hovering over the element).
My second idea was to introduce this flag as a propper state of the SpecialButtonState class
class SpecialButton extends StatefulWidget {
SpecialButton({Key key}) : super(key: key);
#override
SpecialButtonState createState() => SpecialButtonState();
}
class SpecialButtonState extends State<SpecialButton> {
bool active;
#override
void initState() {
super.initState();
this.active = false;
}
activate() {
this.setState(() {
active = true;
});
}
deactivate() {
this.setState(() {
active = false;
});
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: this.active ? COLOR_1 : COLOR_2),
child: null);
}
}
As far as I understood, this would be the correct way to work with flutter but it seems that I can't access the functions "activate" or "deactivate" from either the SpecialButton Class or the Parent Class containing the widget.
So my question is: How can I (directly or indirectly through functions) modify a State from the corresponding StatefulWidget Class or the Parent Widget containing it?
There are already some similar questions about this on here on Stack Overflow where I could find hints both to use or not to use global keys for such behavior which i found misleading. Also, due to the rapid ongoing development of flutter, they are probably outdated so I ask this (similar) question again in relation to this exact use case.
EDIT: I forgot to mention that it is crucial that this flag will be changed after creation therefore It will be changed multiple times during its livetime. This requires the widget to redraw.
It is not neŃessary to use stateful widget for SpecialButton is you case. You can handle active flag with stateless widget and keys. Example code:
class SomeParent extends StatefulWidget {
const SomeParent({Key key}) : super(key: key);
#override
State<SomeParent> createState() => SomeParentState();
}
class SomeParentState extends State<SomeParent> {
bool _button1IsActive = false;
bool _button2IsActive = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
SpecialButton(
key: UniqueKey(),
active: _button1IsActive,
),
SizedBox(height: 8),
SpecialButton(
key: UniqueKey(),
active: _button2IsActive,
),
SizedBox(height: 16),
TextButton(
child: Text('Toggle button 1'),
onPressed: () {
setState(() {
_button1IsActive = !_button1IsActive;
});
},
),
SizedBox(height: 8),
TextButton(
child: Text('Toggle button 2'),
onPressed: () {
setState(() {
_button2IsActive = !_button2IsActive;
});
},
),
],
),
);
}
}
class SpecialButton extends StatelessWidget {
final bool active;
const SpecialButton({Key key, this.active = false}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 40,
width: 40,
decoration: BoxDecoration(color: active ? Colors.red : Colors.blue),
);
}
}
SomeParent is my fantasy, just for example. Don't know what your parent is.
Keys are significant here. They tell widget tree when specific widgets with the same type (such as SpecialButton) should be rebuild.
Please try this approach, it should work.
As nvoigt says, your buttons could even be stateless widget , but their parent should be statefull and you should provide them with the corresponding value. e.g.:
import 'package:flutter/material.dart';
class Parent extends StatefulWidget {
#override
_ParentState createState() => _ParentState();
}
class _ParentState extends State<Parent> {
bool isEnabled = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
StateLessButton1(isEnabled: isEnabled),
StateLessButton1(isEnabled: !isEnabled),
FloatingActionButton(onPressed: (){
setState(() {
isEnabled = !isEnabled;
});
})
],
);
}
}
Now it just depends on when you want to change that value. If you want to change it inside your buttons, I would recommend you to use a class with ChangeNotifier and a function inside it that changes the value. Otherwise I would recommend not to separate your tree into multiple files
I would like to have a text field in a widget where you can search for something. If the string changes, the widget should be reloaded and the new data sent.
I've read many things about a callback function, unfortunately I don't quite understand it at flutter.
Below you will find the sample code:
Thanks for your help
class _HomepageState extends State<Homepage> {
String data;
String day;
...
TextField(
onChanged: (str){
setState(() {
data = str;
});
},
),
...
Nextpage(data: data, day: day,)
...
}
class Nextpage extends StatefulWidget {
final String data;
final String day;
Nextpage({this.data, this.day});
...
print(widget.data);
...
}
Below is an example where you have a TextField, and as its input changes, the text is shown on a different Text widget (you can copy it and paste it to DartPad to see how it works in action).
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String myText = '';
TextField buildTextField() {
return TextField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
onChanged: (changedText) => updateText(changedText),
onEditingComplete: () => print("complete"),
);
}
void updateText(newText) {
setState(() {
myText = newText;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Example",
theme: ThemeData(primarySwatch: Colors.deepPurple),
home: Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
buildTextField(),
Text(myText),
]),
),
));
}
}
The callback is this part of the code:
onChanged: (changedText) => updateText(changedText)
and the callback function is updateText.
This is another example of a callback where the print function (the callback function) is called after the editing is complete.
onEditingComplete: () => print("complete")
I hope this helps.
I'm building an app with a long form in it. So I decided to seperate it into several steps.
Each step would be a widget containing formFields.
So I would have something like this:
int _currentStep = 0;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String _firstname;
String _lastname;
String _city;
List<Widget> formGroups = [
FormGroup1(),
FormGroup2(),
FormGroup3(),
];
The form would bind to the state like this
Form(
key: _formKey,
child: formGroups[_currentStep],
),
My idea is to be able to navigate to the next widget like this
void goToNext() {
setState(() {
if (_currentStep < formGroups.length - 1) {
_currentStep += 1;
}
});
}
Firstly, is it a good practice?
How can I get the main widget to get the input from the children widgets?
For example if the FormGroup2 contains the inputfield to set the _lastname, how can I make it availaibe at the form level?
Thank you for your help.
Whenever you want parent widget to get input from the child widget you always use the NotificationListener at parent and pass Notification containing data from the child.
This technique is used by many flutter widgets like DefaultTabController receives OverscrollNotification when user swipes to the last page and is still trying to swipe.
In your use case you can pass the value notifications from the child Widgets to the Form Widget.
Here is a Demo for your reference Run on dartpad
Following is a working code demonstrating the use of this widget:
import 'package:flutter/material.dart';
main() => runApp(MaterialApp(home: MyApp()));
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _string = 'You haven\'t pressed a button yet' ;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Notification demo'),),
body: NotificationListener<IntegerNotification>(
onNotification: (IntegerNotification notification){
print(notification.value);
setState(() {
_string = 'You have pressed button ${notification.value} times.';
});
return true;
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(_string),
ChildWidget(),
],
),
),
);
}
}
class ChildWidget extends StatefulWidget {
#override
_ChildWidgetState createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
int _counter = 0;
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text('Increment'),
onPressed: () {
IntegerNotification(++_counter).dispatch(context);
},
),
);
}
}
class IntegerNotification extends Notification {
final value;
IntegerNotification(this.value);
}
I hope this helps, in case of any doubt please comment.
I'm new in Flutter and I am following this official example about text fields: https://flutter.dev/docs/cookbook/forms/text-field-changes
There is an axample for listen to changes in the controller of a text field widget. Please note this fragment of code _MyCustomFormState
final myController = TextEditingController();
#override
void initState() {
super.initState();
myController.addListener(_printLatestValue);
}
_printLatestValue() {
print("Second text field: ${myController.text}");
}
If I have two fields and two controllers, I would like to have just one listener, and display some message depending on which controller called the method. I would like to do something like this:
final myController1 = TextEditingController();
final myController2 = TextEditingController();
#override
void initState() {
super.initState();
myController1.addListener(_printLatestValue('message1'));
myController1.addListener(_printLatestValue('message2'));
}
_printLatestValue(message) {
print("Second text field: ${myController.text + message}");
}
which is not possible because the method addListener() uses some called VoidCallback, which have no arguments. At least that is what I understood from the Flutter docs.
So, if it is possible, how can I achieve what I'm looking for?
You're almost correct, but not quite. You're free to pass in any arguments to the listener. However, those arguments need to come from somewhere else - TextEditingController does not supply any, and it does not expect any return values. In other words, the signature should be something like: () => listener(...).
So to answer your question, you're free to do something like the following to distinguish the controllers:
void initState() {
super.initState();
firstController.addListener(() => _printLatestValue('first'));
secondController.addListener(() => _printLatestValue('second'));
}
Full working example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Text controllers',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final firstController = TextEditingController();
final secondController = TextEditingController();
void initState() {
super.initState();
firstController.addListener(() => _printLatestValue('first'));
secondController.addListener(() => _printLatestValue('second'));
}
#override
void dispose() {
firstController.dispose();
secondController.dispose();
super.dispose();
}
_printLatestValue(message) {
if (message == 'first') {
print('Received form first controller: ${firstController.text}');
} else {
print('Received from second controller: ${secondController.text}');
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Controllers', style: TextStyle(fontSize: 18)),
),
body: Center(
child: Column(
children: <Widget>[
TextField(controller: firstController,),
TextField(controller: secondController,)
],
),
),
);
}
}
Note that in this case, listener will only print the text from a TextField that was changed.
I have a Flutter where I display a list of elements in a Column, where the each item in the list is a custom widget. When I update the list, my UI doesn't refresh.
Working sample:
class Test extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return TestState();
}
}
class TestState extends State<Test> {
List<String> list = ["one", "two"];
final refreshKey = new GlobalKey<RefreshIndicatorState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.all(40),
child: Row(
children: <Widget>[
Container(
child: FlatButton(
child: Text("Update"),
onPressed: () {
print("Updating list");
setState(() {
list = ["three", "four"];
});
},
)
),
Column(
children: list.map((s) => ItemView(s)).toList(),
)
],
),
)
);
}
}
class ItemView extends StatefulWidget {
String s;
ItemView(this.s);
#override
State<StatefulWidget> createState() => ItemViewState(s);
}
class ItemViewState extends State<ItemView> {
String s;
ItemViewState(this.s);
#override
Widget build(BuildContext context) {
return Text(s);
}
}
When I press the "Update" button, my list is updated but the UI is not. I believe this has something to do with using a custom widget (which is also stateful) because when I replace ItemView(s) with the similar Text(s), the UI updates.
I understand that Flutter keeps a track of my stateful widgets and what data is being used, but I'm clearly missing something.
How do I get the UI to update and still use my custom widget?
You should never pass parameters to your State.
Instead, use the widget property.
class ItemView extends StatefulWidget {
String s;
ItemView(this.s);
#override
State<StatefulWidget> createState() => ItemViewState();
}
class ItemViewState extends State<ItemView> {
#override
Widget build(BuildContext context) {
return Text(widget.s);
}
}