Deleting a widget from a list of widgets [Flutter] - flutter

In a flutter application that I'm building(a to-do list basically), I wish to delete all the completed tasks(active checkboxes) with a single button.
As of now, it functions as expected ONLY WHEN the last checkbox is active and all the other active checkboxes(if any) are right above it, simultaneously.
The app malfunctions if there is even 1 inactive checkbox after an active checkbox.
Here's the code for the class that creates the task widget :
class addnote extends StatefulWidget {
final String task_txt;
final int index;// receives the value
addnote({ Key key, this.task_txt, this.index }): super(key: key);
#override
_addnoteState createState() => _addnoteState();
}
class _addnoteState extends State<addnote> {
bool value=false;
Widget txt_strike(String to_strike, bool str_value){
return str_value ?
AutoSizeText(to_strike,style: TextStyle(
decoration: TextDecoration.lineThrough,
fontFamily: "Quicksand",
fontSize: 20.0,
color: Colors.grey,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
)
:
AutoSizeText(to_strike,style: TextStyle(
//decoration: TextDecoration.lineThrough,
fontFamily: "Quicksand",
fontSize: 20.0,
color: Colors.black,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
);
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius:BorderRadius.circular(4.0),
boxShadow: [BoxShadow(
color:Colors.grey,
offset: Offset(-6.0,4.0),
blurRadius: 4.0,
)],
color: Colors.white
),
margin: EdgeInsets.symmetric(vertical: 5.0,horizontal: 3.0),
child:InkWell(
onTap: (){setState(() {
value=!value;
w_checks[widget.index]=!w_checks[widget.index];
});},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(flex:1,
child: CircularCheckBox(
disabledColor: Colors.white,
activeColor: Colors.green,
value: value,
onChanged:(bool _changed)
{
// print(w_checks[Index]);
setState(() {
value=!value;
w_checks[widget.index]=!w_checks[widget.index];
});
}),
),
Expanded(flex:5,
child: txt_strike(widget.task_txt, value)),
],
),
)
);
}
}
And here's the code for the func that deletes the task widget :
void del_task(){
int count=0;
for(int i=0; i<w_checks.length; i++)
{
if(w_checks[i]==true)
count++;
}
while(count>=0)
{
for(int j=0; j<w_checks.length; j++)
{
if(w_checks[j]==true)
{
setState(() {
{ w_tasks.removeAt(j); //w_tasks is the list of all the tasks
w_checks.removeAt(j); //w_checks is the list that stores bool values corresponding to each checkbox
}
});
for(int k=j; k<w_checks.length; k++)
{
w_tasks[k]=w_tasks[k+1];
w_checks[k]=w_checks[k+1];
}
break;
}
}
count--;
}
}
Hope I was able to describe my problem, kindly help.

I'm not really shure about what are you doing inside del_task() but I think your problem is caused by the for cycle in which you are moving all later objects down by one position.
That operation is already performed by the "list.removeAt(index)" method, as u can see from the documentation: https://api.dart.dev/stable/2.10.2/dart-core/List/removeAt.html
I would have changed the code like this:
void del_task(){
for(int i=0; i<w_checks.length; i++)
{
if(w_checks[i]==true)
{
setState(() {
w_tasks.removeAt(i);
w_checks.removeAt(i);
});
i--;
}
}
}
I don't understand why you needed the count variable.
The code I posted should iterate throught w_checks.
When it found a "true" value, it will call removeAt(i) and then decrease index by one.

Related

What can I do to make my ListView stop incrementing the data every time I open it?

My first Flutter project, which is a tricycle booking system, has just begun. Using the ListView widget, I wanted to display all of the active passengers that are saved in my Firebase Database. However, when I attempted to display it and place it in a List, all functions are working fine at first click. When you click the button to view the ListView a second time, all of the saved data are replicated. The list continues after my third click and grows by three. The image below illustrates what takes place when I repeatedly click on the ListView.
These are the blocks of code that are utilized for this functionality:
CODE for Functionality
retrieveOnlinePassengersInformation(List onlineNearestPassengersList) async
{
dList.clear();
DatabaseReference ref = FirebaseDatabase.instance.ref().child("passengers");
for(int i = 0; i<onlineNearestPassengersList.length; i++)
{
await ref.child(onlineNearestPassengersList[i].passengerId.toString())
.once()
.then((dataSnapshot)
{
var passengerKeyInfo = dataSnapshot.snapshot.value;
dList.add(passengerKeyInfo);
print("passengerKey Info: " + dList.toString());
});
}
}
CODE for the UI
body: ListView.builder(
itemCount: dList.length,
itemBuilder: (BuildContext context, int index)
{
return GestureDetector(
onTap: ()
{
setState(() {
chosenPassengerId = dList[index]["id"].toString();
});
Navigator.pop(context, "passengerChoosed");
},
child: Card(
color: Colors.grey,
elevation: 3,
shadowColor: Colors.green,
margin: EdgeInsets.all(8.0),
child: ListTile(
leading: Padding(
padding: const EdgeInsets.only(top: 2.0),
child: Icon(
Icons.account_circle_outlined,
size: 26.sp,
color: Color(0xFF777777),
),
),
title: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Text(
dList[index]["first_name"] + " " + dList[index]["last_name"],
style: TextStyle(
fontFamily: "Montserrat",
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
Icon(
Icons.verified_rounded,
color: Color(0xFF0CBC8B),
size: 22.sp,
),
],
),
],
),
),
),
);
},
),
Expected Result:
Actual Result AFTER CLICKING MANY TIMES:
Made a demo for you how to call function once on load
class CustomWidgetName extends StatefulWidget {
const CustomWidgetName({Key? key}) : super(key: key);
#override
State<CustomWidgetName> createState() => _CustomWidgetNameState();
}
class _CustomWidgetNameState extends State<CustomWidgetName> {
List? dList = [];
void myDataFunction() async {
// do your data fetch and add to dList
final newList = [];
setState(() {
dList = newList;
});
}
#override
void initState() {
super.initState();
myDataFunction(); // Call your async function here
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
Try this solution.
Update SelectNearestActiveDriversScreen() like this:
class SelectNearestActiveDriversScreen extends StatefulWidget
{
DatabaseReference? referenceRideRequest;
final List list;
SelectNearestActiveDriversScreen({this.referenceRideRequest, required this.list});
#override
State<SelectNearestActiveDriversScreen> createState() => _SelectNearestActiveDriversScreenState();
}
In homepage.dart, declare List dList = [];, then change line 378 like this:
Navigator.push(context, MaterialPageRoute(builder: (c)=> SelectNearestActiveDriversScreen(list: dList)));
In SelectNearestActiveDriversScreen(), replace all dList with widget.list.
Finally, if you are using variables in a specific file declare them in that file(not in another file) or pass them in the constructor of the class / file / widget /screen you are calling.
If you would rather use global variables and state managers go for packages like GetX.

Flutter ValueListenableBuilder result updates state to show/ hide widget

I am trying to use my ValueListenableBuilder, which generates Yes/ No buttons, to determine whether or not a textformfield will be visible. I.e. user selects the "Yes" button and the state of the app changes to allow the hidden textformfield to be displayed. I am extremely puzzled as to how I can either use setState, NotifyListeners, or ChangeNotifier to accomplish this task.
I am trying to avoid using either a radio button or making buttons outside of the ValueListenableBuilder because my ValueListenableBuilder is designed to generate a lot of my other buttons and I was hoping to incorporate one more function into them. Thanks in advance!
ValueListenableBuilder
ValueListenableBuilder<Option>(
valueListenable: yesNo,
builder: (context, option, _) => MakeButtons(
num0: 0,
num1: 1,
makeButtonWidth: MediaQuery.of(context).size.width * 0.20,
selected: option,
onChanged: (newOption) =>
yesNo.option = newOption,
ifSelected: (newOption) {
setState(() {
yesNo.option = newOption;
yesNo;
});
},
),
),
Make Buttons
enum Option {
option0,
option1,
}
class MakeButtons extends StatefulWidget {
MakeButtons({
this.num0,
this.num1,
this.selected,
this.onChanged,
this.ifSelected,
this.makeButtonWidth,
});
final int num0;
final int num1;
final double makeButtonWidth;
final Option selected;
final Function ifSelected;
final ValueChanged<Option> onChanged;
#override
_MakeButtonsState createState() => _MakeButtonsState();
}
class _MakeButtonsState extends State<MakeButtons> {
List<Widget> makeButtons(int num0, int num1, List<Widget> children,
List<Color> colors, List<Function> onPresses) {
List<Widget> buttons = new List();
for (int i = num0; i < num1; i++) {
buttons.add(Container(
constraints: BoxConstraints(
minWidth: widget.makeButtonWidth,
),
child: RectButton(
buttonChild: children[i],
bgColor: colors[i],
onPress: onPresses[i]),
));
}
return buttons;
}
Option selectedOption;
#override
Widget build(BuildContext context) {
List<Widget> children = [
AutoSizeText(
'Yes',
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.w600, color: Colors.white),
),
AutoSizeText(
'No',
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.w600, color: Colors.white),
),
];
List<Color> colors = [
selectedOption == Option.option0
? kActiveButtonColor
: kInactiveButtonColor,
selectedOption == Option.option1
? kActiveButtonColor
: kInactiveButtonColor,
];
List<Function> onPresses = [
() {
setState(() {
selectedOption = Option.option0;
});
return widget.onChanged(Option.option0);
},
() {
setState(() {
selectedOption = Option.option1;
});
return widget.onChanged(Option.option1);
},
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children:
makeButtons(widget.num0, widget.num1, children, colors, onPresses),
);
}
}
Visibility
visible: yesNo.title == 'A' ||
yesNo == 'Yes',
child: InputRow(
myUnit: defaultUnit,
inputParameter: 'Units',
textField: unitController,
colour: kEmoryDBlue,
),
),

Show counter to number of elements hidden when overflow occurs in flutter row widget

Can anyone please help to implement this feature of Gmail that shows the counter to number of emails hidden when the email list becomes large ? I want to implement this in row widget where instead of being scrollable extra elements count is shown when overflow occurs.Gmail shows +15 counter for hidden emails
I was Curious to give a try to achieve the same effect, as asked.
Just in case, If anyone want a start for writing a custom one, then below code may help.
Here is my Code, Feel free to give any suggestions,
(For Now delete button in chips is not working bcoz of some logic problem, I will make it work another day)
import 'package:flutter/material.dart';
class Demo3 extends StatefulWidget {
#override
_Demo3State createState() => _Demo3State();
}
class _Demo3State extends State<Demo3> {
String temp = "";
bool showChips = false;
List<Widget> chipsList = new List();
TextEditingController textEditingController = new TextEditingController();
final _focusNode = FocusNode();
int countChipsToDeleteLater = 0;
#override
void initState() {
super.initState();
_focusNode.addListener(() {
print("Has focus: ${_focusNode.hasFocus}");
if (!_focusNode.hasFocus) {
showChips = false;
setState(() {});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: new Container(
height: 500,
child: new Center(
child: Container(
width: 300,
child: !showChips
? Row(
children: [
buildTextField(),
showNumberWidgetIfAny(),
],
)
: Center(
child: Wrap(
children: [
Wrap(
children: buildChips(),
),
buildTextField(),
],
),
),
),
),
),
),
);
}
buildChips() {
return chipsList;
}
buildTextField() {
return Container(
width: 200,
child: new TextField(
showCursor: true,
focusNode: _focusNode,
autofocus: true,
cursorColor: Colors.black,
style: new TextStyle(fontSize: 22.0, color: Colors.black),
controller: textEditingController,
// decoration: InputDecoration.collapsed(
// hintText: "",
// ),
onChanged: (value) {
if (value.contains(" ")) {
checkWhatToStoreInChips(value, countChipsToDeleteLater);
textEditingController.clear();
setState(() {
showChips = true;
});
countChipsToDeleteLater++;
}
},
),
);
}
checkWhatToStoreInChips(String val, int chipsIndex) {
temp = "";
for (int i = 0; i < val.length; i++) {
if (val[i] == " ") {
break;
}
temp = temp + val[i];
}
addToChips(temp, chipsIndex);
}
addToChips(String tmp, int chipsIndex) {
chipsList.add(Chip(
// onDeleted: () {
// if (chipsList.length == 0) {
// countChipsToDeleteLater = 0;
// }
// chipsList.removeAt(chipsIndex);
// print(chipsList.length);
// print(chipsIndex);
// setState(() {});
// },
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade800,
child: Text(tmp[0]),
),
label: Text(temp),
));
}
showNumberWidgetIfAny() {
int len = chipsList.length;
if (len >= 1) {
return GestureDetector(
onTap: () {
showChips = true;
setState(() {});
},
child: new Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.blue,
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Text(
"${chipsList.length.toString()} ",
style: new TextStyle(color: Colors.white, fontSize: 22),
),
),
),
);
}
return Container();
}
}
How it works:
Write something in text field, then press space, showChips boolean will become true
onChanged will detect the space and will send the string to a function.
That function will extract the string before space and then will add the string to a chip,
Finally the chip will be added to a chipslist.
We will have a boolean variable to check if the textfield is in focus and when to show the textfield and numberwidget (a widget which will keep count of the total chips, same like you asked in your question) or when to show the chipslist and textfield wraped in a wrap widget.
You can play around by changing the decoration of textfield to collapsed, to it look like the same as gmail.
Check this package, if you want to use custom package for ease.
I was facing a similar issue. I found a way to implement the Overflow count text.
Sample image
You basically have to paint the overflow text, and get its width like below
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style),
textDirection: TextDirection.ltr,
textScaleFactor: WidgetsBinding.instance.window.textScaleFactor,
)..layout();
var textSize = textPainter.size;
textSize.width;
Then subtract that from the width available. Lets call it x.
Then create a sum of width for each row item(using TextPainter.layout() method mentioned above), till its value is less than x.
This way you'll know how many items can be shown in the row.
I have created a Flutter library to help with this.

How to access a widgets state from a stateful widget class Flutter

Sorry if this has been already answered somewhere else but I am new to Flutter. I have a toString method in my widget below that needs to access the state of the widget to output the string. The widget is a card that contains a text field and other text-related operations. To store information on what a user types into the card I need to get all the data into one string which toString returns.
class TextCard extends StatefulWidget {
_TextCardState cardState = _TextCardState();
TextCard({String text = ""}) {
cardState.textController.text = text;
}
#override
_TextCardState createState() => cardState = new _TextCardState();
String toString({DiagnosticLevel minLevel = DiagnosticLevel.debug}) {
return delimiter2 +
"TextCard" +delimiter3 +
cardState.getText() +
delimiter3 +
(cardState.center.toString()) +
delimiter3 +
cardState.bold.toString() +
delimiter3 +
cardState.italic.toString() +
delimiter3 +
cardState.size.toString() +
delimiter2;
}
}
The widget also takes in a string value to set the initial value of a text field in the state below
class _TextCardState extends State<TextCard> {
double size = 18;
bool bold = false;
bool italic = false;
bool center = false;
var textController = TextEditingController();
#override
Widget build(BuildContext context) {
return Container(
height: _cardSizeY,
width: _cardSizeX,
child: Card(
elevation: _elevation,
child: Center(
child: Column(children: [
ListTile(leading: Icon(Icons.text_fields)),
ButtonBar(children: [
IconButton(
icon: Icon(Icons.format_bold),
onPressed: () {
updateText(size, !bold, italic, center);
},
),
IconButton(
icon: Icon(Icons.format_italic),
onPressed: () {
updateText(size, bold, !italic, center);
},
),
Slider(
value: size,
max: 80,
min: 1,
onChanged: (size) {
updateText(size, bold, italic, center);
})
]),
TextField(
maxLines: null,
style: TextStyle(
fontWeight: (bold) ? FontWeight.bold : FontWeight.normal,
fontStyle: (italic) ? FontStyle.italic : FontStyle.normal,
fontSize: size),
textAlign: (center) ? TextAlign.center : TextAlign.start,
controller: textController,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
borderRadius: BorderRadius.all(Radius.circular(10)))))
]))));
}
void updateText(double size, bool bold, bool italic, bool center) {
setState(() {
this.size = size;
this.bold = bold;
this.italic = italic;
this.center = center;
});
}
String getText() {
return textController.value.text;
}
}
When I run this code I get the error the create state function returned an old invalid state instance.
I have looked into putting the text controller into the _TextCardState() class but I would not be able to change the initial value of the TextField.
So I see what you are trying to do here but there are better ways to access the value of a textfield from outside of the class.
Instead of access your toString method from outside, which relies on a values from the private state class, I suggest a state management solution that will make this way easier and cleaner. You'll also have easier access to all those variables you need.
What you're doing here is not something that's meant to be done, which is why you're getting those state errors.
_TextCardState cardState = _TextCardState();
Here's a way to do it using GetX.
All your data will live in a GetX Controller class below and will be used in your now stateless TextCard widget.
class Controller extends GetxController {
var textController = TextEditingController();
String textfieldString = '';
double size = 18;
bool bold = false;
bool italic = false;
bool center = false;
#override
void onInit() {
super.onInit();
// updates the value of textfieldString anytime the user types
textController.addListener(() {
textfieldString = textController.text;
debugPrint(textController.text);
});
}
// this method lives in this class and is accessible from anywhere. The
// only thing not clear is what delimier2 is and where it comes from
// toString is not a good name because that is an overridden method that lives
// in most Dart classes
String buildString({DiagnosticLevel minLevel = DiagnosticLevel.debug}) {
return delimiter2 +
"TextCard" +delimiter3 +
textfieldString +
delimiter3 +
(center.toString()) +
delimiter3 +
bold.toString() +
delimiter3 +
italic.toString() +
delimiter3 +
size.toString() +
delimiter2;
}
// single responsibility methods as opposed to firing one big function
// multiple times when its only affecting one variable
void toggleBold() {
bold = !bold;
update();
}
void toggleItalic() {
italic = !italic;
update();
}
void toggleCenter() {
center = !center;
update();
}
void updateSize(double sliderValue) {
size = sliderValue;
update();
}
}
Put this in your main before running your app. Can be done anywhere as long as its before you try and access the controller.
Get.put(Controller());
And here is your TextCard widget
class TextCard extends StatelessWidget {
#override
Widget build(BuildContext context) {
final controller =
Get.find<Controller>(); // finding the initalized controller
return Container(
height: _cardSizeY,
width: _cardSizeX,
child: Card(
elevation: 20,
child: Center(
child: Column(
children: [
ListTile(leading: Icon(Icons.text_fields)),
ButtonBar(children: [
IconButton(
icon: Icon(Icons.format_bold),
onPressed: () {
controller.toggleBold();
},
),
IconButton(
icon: Icon(Icons.format_italic),
onPressed: () {
controller.toggleItalic(); // accessing method via controller
},
),
// GetBuilder rebuilds children when value of controller variable changes
GetBuilder<Controller>(
builder: (_) {
return Slider(
value: controller
.size, // accessing size in other class via controller
max: 80,
min: 1,
onChanged: (value) {
controller.updateSize(value);
});
},
)
]),
GetBuilder<Controller>(
builder: (_) {
return TextField(
maxLines: null,
style: TextStyle(
fontWeight: (controller.bold)
? FontWeight.bold
: FontWeight.normal,
fontStyle: (controller.italic)
? FontStyle.italic
: FontStyle.normal,
fontSize: controller.size),
textAlign: (controller.center)
? TextAlign.center
: TextAlign.start,
controller: controller.textController,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
borderRadius: BorderRadius.all(
Radius.circular(10),
),
),
),
);
},
)
],
),
),
),
);
}
}
So where ever you are in your app where you need that function, find the controller and get your value.
final controller = Get.find<Controller>():
final newString = controller.buildString();
This will be easier and use less memory because TextCard is now stateless.

Connecting multiple text fields to act like a single field in Flutter

We are busy creating a mobile application in Flutter that relates to credit cards. In our design, we have planned to capture the numeric fields for the card in VIN number and expiry date using 4 separate fields, as shown in the below image (I am sure you have seen similar implementations on other apps):
What is important here is that these 4 fields still need to act like a single field, namely if you type it needs to jump to the next one, if you delete or press left it needs to jump to the previous one.
We have tried two different approaches that are both giving us issues:
Use four different fields - This worked somewhat well, but became buggy really fast when the user deletes or tried to navigate between numbers.
Use a single input field with expanded letterSpacing four lines drawn underneath - This again works somewhat well, but since the font we are using is not monospaced (letters and numbers that are all the same size) the numbers do not really line up properly with the lines underneath, making it look rather terrible.
I have done some searching, but have yet to find someone who has done something similar that have posted about it online. It is somewhat difficult to make Google understand what I am asking, which is also adding to the difficulty in finding a solution.
Does anyone know of an example out there that might point me in the right direction, or does anyone on here perhaps have any clever ideas about how this might be achieved? Any advice would be greatly appreciated!
PS:
Although it is a but convoluted, please see our multiple input field code below:
Multiple texts fields:
import 'package:creditcardcurator/widgets/textFields/single_number_textfield.dart';
import 'package:flutter/material.dart';
import 'package:print_color/print_color.dart';
var focusNodes;
bool getFirstFieldFocus = true;
class ExpiryDateTextField extends StatefulWidget {
final List<TextEditingController> controllers;
final Function onChangeF;
final Function onComplete;
final bool startFocus;
final FocusNode focusNode;
final bool isDisbaled;
void requestFocus() {
Print.red(getFirstFieldFocus.toString());
if (getFirstFieldFocus) focusNodes[0].requestFocus();
}
ExpiryDateTextField(
{this.controllers,
this.onChangeF,
this.onComplete,
this.startFocus = false,
this.focusNode,
this.isDisbaled = false});
#override
_ExpiryDateTextFieldState createState() => _ExpiryDateTextFieldState();
}
class _ExpiryDateTextFieldState extends State<ExpiryDateTextField> {
#override
void dispose() {
// TODO: implement dispose
super.dispose();
}
#override
void initState() {
super.initState();
focusNodes = [
widget.focusNode,
FocusNode(),
FocusNode(),
FocusNode(),
];
getFirstFieldFocus = true;
if (widget.startFocus) widget.requestFocus();
}
#override
Widget build(BuildContext context) {
if (widget.startFocus) widget.requestFocus();
bool onSwitchChanged(value, context, index) {
getFirstFieldFocus = false;
if (index == 4) {
//if it is on the last text box, do nothing
} else {
if (widget.controllers[index].text.length > 0) {
index++;
FocusScope.of(context).requestFocus(focusNodes[index]);
widget.controllers[index].selection = TextSelection(
baseOffset: 0,
extentOffset: widget.controllers[index].text.length);
// FocusScope.of(context).focus
}
}
return true;
}
return Row(
children: <Widget>[
Expanded(
flex: 1,
child: SingleDigitTextField(
isDisbaled: widget.isDisbaled,
onChangedF: (value) {
widget.onChangeF(value, 0);
// print(this.toString(minLevel: DiagnosticLevel.debug));
onSwitchChanged(value, context, 0);
},
fNode: focusNodes[0],
cController: widget.controllers[0]),
),
Expanded(
flex: 1,
child: SingleDigitTextField(
isDisbaled: widget.isDisbaled,
onChangedF: (value) {
widget.onChangeF(value, 1);
onSwitchChanged(value, context, 1);
},
fNode: focusNodes[1],
cController: widget.controllers[1]),
),
Expanded(
flex: 1,
child: Text("/",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.display2),
),
Expanded(
flex: 1,
child: SingleDigitTextField(
isDisbaled: widget.isDisbaled,
onChangedF: (value) {
widget.onChangeF(value, 2);
onSwitchChanged(value, context, 2);
},
fNode: focusNodes[2],
cController: widget.controllers[2]),
),
Expanded(
flex: 1,
child: SingleDigitTextField(
isDisbaled: widget.isDisbaled,
onChangedF: (value) {
widget.onChangeF(value, 3);
if (value != null && value.length != 0) {
try {
widget.onComplete();
} catch (e) {
print(e.toString());
}
}
onSwitchChanged(value, context, 3);
},
fNode: focusNodes[3],
cController: widget.controllers[3],
onComplete: widget.onComplete,
),
),
],
);
}
}
Single text field:
import 'package:creditcardcurator/utils/page_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class SingleDigitTextField extends StatelessWidget {
final Function onChangedF;
final FocusNode fNode;
final TextEditingController cController;
final Function onComplete;
final bool isDisbaled;
// final Widget child;
// DollarTextField({this.child});
SingleDigitTextField(
{this.onChangedF,
this.fNode,
this.cController,
this.onComplete,
this.isDisbaled = false});
void defaultFunction() {
print("default function actioned");
}
#override
Widget build(BuildContext context) {
return Container(
// margin: const EdgeInsets.all(8.0),
padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 0.0),
width: 50,
child: TextField(
enabled: !isDisbaled,
inputFormatters: [
WhitelistingTextInputFormatter(new RegExp('[0-9,.]'))
],
controller: cController,
onTap: () {
// this.cController.selection = TextSelection.fromPosition(
// TextPosition(offset: this.cController.text.length)); //cursor to end of textfield
cController.selection = TextSelection(
baseOffset: 0,
extentOffset: cController.text.length); //to begining of textfield
},
focusNode: fNode,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: getd3FontSize(context),
fontFamily: getFontFamily(context),
color: Colors.white,
),
maxLength: 1,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: -20),
counter: null,
helperStyle: TextStyle(
color: Colors.transparent,
), //hiding the max length hint text
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
),
keyboardType:
TextInputType.numberWithOptions(signed: true, decimal: true),
// keyboardType: TextInputType.number,
onChanged: (e) {
onChangedF(e);
},
onEditingComplete: () {
try {
onComplete();
} catch (e) {
print(e.toString());
}
},
),
);
}
}