How to display data in a table? - flutter

I need to display the data that comes to me from the server as an array of objects. The number of objects may vary.
For example -
{"RowNumber":1,"WalletName":"Elsom","PayerPhoneNumber":"996555121212","CreatedDate":"2022-06-10T10:52:00","Amount":50.2,"CurrencyCode":"KGS"},
{"RowNumber":2,"WalletName":"O!","PayerPhoneNumber":"996555131313","CreatedDate":"2022-06-09T22:12:00","Amount":122.3,"CurrencyCode":"KGS"},
You need to display them in the form of a table, how to do this - I don’t understand at all, I processed the response from the server. I made a cycle, but how can I display it on the screen with such a code structure? -
class Report extends StatelessWidget {
var ressultat = json.decode(MyApp.resultat)['Transactions']; //here is an array of objects!!!!!
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: , //HERE HERE HERE
],
),
);
}
}
And where can I put the loop? -
var ress = json.decode(MyApp.resultat)['Transactions'];
print(ress[5]['Amount']);
for (int i = 0; i <= ress.length; i++) {
print(ress[i]);
}

I had a similar problem when wanting to see what was returning from a databse on the screen and slapped this together. It's by no means pretty but it does the job, just pass in a Map<String, dynamic> and a String title.
class Tabler extends StatelessWidget {
const Tabler({Key? key, required this.dataMap, required this.title})
: super(key: key);
final Map<String, dynamic> dataMap;
final String title;
#override
Widget build(BuildContext context) {
List<Widget> dataColumns = [];
for (var v in dataMap.values) {
dataColumns.add(_TablerBlock(
dataBlock: v,
));
}
return DefaultTextStyle(
style: TextStyle(fontSize: 25, color: Colors.black),
child: Container(
width: 400,
child: Column(children: <Widget>[
Text(dataMap.toString()),
Text(title),
SizedBox(height: 20),
...dataColumns
])));
}
}
class _TablerBlock extends StatelessWidget {
const _TablerBlock({Key? key, required this.dataBlock}) : super(key: key);
final dynamic dataBlock;
#override
Widget build(BuildContext context) {
List<Widget> block = [];
if (dataBlock is Map<String, dynamic>) {
for (var v in dataBlock.entries) {
block.add(_TablerRow(
dataRow: [v.key, v.value],
));
}
}
return Container(
child: Column(children: <Widget>[
...block,
]));
}
}
class _TablerRow extends StatelessWidget {
const _TablerRow({Key? key, required this.dataRow}) : super(key: key);
final List<dynamic> dataRow;
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(dataRow[0].toString() + ': '),
Text(dataRow[1].toString()),
],
);
}
}
Use it by calling
Center(
child: Tabler(dataMap: yourMap, title: 'title');
)
Note that it only works for a single Map.

Related

Flutter: remove an element in the List<ObjectWidget> with index is correct but invalid in the List<Widget>

I have the list of an object and in the object have the widget.
The List<Object> can add or remove the object.
When I remove the object in this list, the value in this object is correct. but the widget in this object is incorrect.
Why? The widget in the Object should belong to this object. This should be correct. How to fix this?
example code:
Try to add a field 2 times and type the name of the first field with 'A' and 'B' for the second then remove the first field('A' should be removed). the rest of the field will show 'A'.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: Scaffold(body: Center(child: MyWidget())));
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Testpage();
}
}
class Testpage extends StatefulWidget {
const Testpage({Key? key}) : super(key: key);
#override
State<Testpage> createState() => _TestpageState();
}
class _TestpageState extends State<Testpage> {
List<TestWidgetGroup> fieldList = [];
#override
Widget build(BuildContext context) {
print('\nBuild\n');
List<Widget> children = [];
for (int index = 0; index < fieldList.length; index++) {
print(
'\nindex at $index, name = ${fieldList[index].object.name}, phone = ${fieldList[index].object.phone}'); // correct value
children.add(Padding(
padding: const EdgeInsets.all(10.0),
child: Column(children: [
fieldList[index].nameField,
fieldList[index].phoneField,
Center(
child: TextButton(
onPressed: () => setState(() => fieldList.removeAt(index)),
child: const Text('remove'))),
]),
));
}
return Scaffold(
backgroundColor: Colors.brown,
body: SafeArea(
child: Column(
children: children +
[
Center(
child: TextButton(
onPressed: () =>
setState(() => fieldList.add(TestWidgetGroup())),
child: const Text('add')))
],
)));
}
}
class TestWidgetGroup {
TestObject object = TestObject();
late Widget nameField =
buildTextField((v) => object.name = v, 'name: ${object.name}');
late Widget phoneField =
buildTextField((v) => object.phone = v, 'phone: ${object.phone}');
}
class TestObject {
String? name;
String? phone;
}
Widget buildTextField(Function(String?) onChanged, String text) {
print(text);
return TextFormField(onChanged: onChanged);
}
Now I can do it by using the Key. Add List<Key> fieldKeyList = []; with a unique string.
code:
import 'package:flutter/material.dart';
import 'package:mongo_dart/mongo_dart.dart' as mongo;
class Testpage extends StatefulWidget {
const Testpage({Key? key}) : super(key: key);
#override
State<Testpage> createState() => _TestpageState();
}
class _TestpageState extends State<Testpage> {
List<TestWidgetGroup> fieldList = [];
List<Key> fieldKeyList = [];
#override
Widget build(BuildContext context) {
print('\nBuild\n');
List<Widget> children = [];
for (int index = 0; index < fieldList.length; index++) {
print('\nindex at $index, name = ${fieldList[index].object.name}, phone = ${fieldList[index].object.phone}'); // correct value
children.add(Padding(
key: fieldKeyList[index],
padding: const EdgeInsets.all(10.0),
child: Column(children: [
fieldList[index].nameField,
fieldList[index].phoneField,
Center(
child: TextButton(
onPressed: () {
fieldKeyList.removeAt(index);
setState(() => fieldList.removeAt(index));
},
child: const Text('remove'))),
]),
));
}
return Scaffold(
backgroundColor: Colors.brown,
body: SafeArea(
child: Column(
children: children +
[
Center(
child: TextButton(
onPressed: () {
fieldKeyList.add(Key(mongo.ObjectId().$oid));
setState(() => fieldList.add(TestWidgetGroup()));
},
child: const Text('add')))
],
)));
}
}
class TestWidgetGroup {
TestObject object = TestObject();
late Widget nameField = buildTextField((v) => object.name = v, 'name: ${object.name}');
late Widget phoneField = buildTextField((v) => object.phone = v, 'phone: ${object.phone}');
}
class TestObject {
String? name;
String? phone;
}
Widget buildTextField(Function(String?) onChanged, String text) {
print(text);
return TextFormField(onChanged: onChanged);
}
However, why does the flutter make the controller remove always remove the last of the list instead of the target index?

Stateless widgets are being called multiple times

I have come across a strange issue. While implementing a functionality, I noticed that all of my widgets functions are called continuously, resulting in high CPU consumption. To prevent this, I changed all my widgets functions to stateless widgets but unfortunately, the problem still persists. Can anyone guide me as to why this is happening or where I am going wrong?
class BearbeitungWidget extends StatelessWidget {
const BearbeitungWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Consumer<EAProvider>(
builder: (context, v, child) => Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Visibility(
visible: v.expandBearWidget,
child: SizedBox(
child: Row(
children: [
SizedBox(
child: Column(
children: const [
SizedBox(child: Text('Vorgang')),
SizedBox(child: Text('Maßnahme')),
],
),
),
// this is called multiple times
_BearbeitungItemWidget(
itemText: 'Technische Prüfung (E)',
gridLength: 11,
backWidgetColor: const Color.fromRGBO(250, 80, 80, 1),
frontWidgetSize: 0.01,
includeIcons: true),
],
),
))
],
),
),
);
}
}
class _BearbeitungItemWidget extends StatelessWidget {
String itemText;
int gridLength;
Color backWidgetColor;
double frontWidgetSize;
bool includeIcons = false;
_BearbeitungItemWidget(
{Key? key,
required this.itemText,
required this.gridLength,
required this.backWidgetColor,
required this.frontWidgetSize,
this.includeIcons = false})
: super(key: key);
#override
Widget build(BuildContext context) {
print('_BearbeitungItemWidget CALLED');
return SizedBox(
child: Column(
children: [
Container(
child: const Text('Maßnahme'),
),
SizedBox(
// this is called multiple times
child: _StackedItemWidget(
backWidgetColor: backWidgetColor,
frontWidgetSize: frontWidgetSize,
includeIcons: includeIcons),
),
// this is called multiple times
_NumberGridWidget(length: gridLength),
],
),
);
}
}
class _NumberGridWidget extends StatelessWidget {
int length;
_NumberGridWidget({Key? key, required this.length}) : super(key: key);
#override
Widget build(BuildContext context) {
print('_NumberGridWidget CALLED');
return Container(
child: Wrap(
children: [
for (var i = 0; i < length; i++)
// this is called multiple times
_GridItemWidget(
text: i,
)
],
),
);
}
}
class _GridItemWidget extends StatelessWidget {
int text;
_GridItemWidget({Key? key, required this.text}) : super(key: key);
#override
Widget build(BuildContext context) {
print('_GridItemWidget CALLED');
return Container(
child: const Text('Maßnahme'),
);
}
}
class _StackedItemWidget extends StatelessWidget {
Color backWidgetColor;
double frontWidgetSize;
bool includeIcons = false;
_StackedItemWidget(
{Key? key,
required this.backWidgetColor,
required this.frontWidgetSize,
this.includeIcons = false})
: super(key: key);
#override
Widget build(BuildContext context) {
print('_StackedItemWidget CALLED');
return Stack(
children: [
// this is called multiple times
_StackedChildItemWidget(
textColor: backWidgetColor,
width: MediaQuery.of(context).size.width * 0.10,
includeIcons: includeIcons),
],
);
}
}
class _StackedChildItemWidget extends StatelessWidget {
Color? textColor;
double? width;
bool includeIcons = false;
_StackedChildItemWidget(
{Key? key, this.textColor, this.width, this.includeIcons = false})
: super(key: key);
#override
Widget build(BuildContext context) {
print('_StackedChildItemWidget CALLED');
return Container(
child: Center(
child: const Text('Maßnahme'),
),
);
}
}

Flutter: How to change the state from inside a child widget of AnimatedSwitcher

I have created a screen in flutter that shows a question and displays an array of possible answers as buttons. The questions and answers are inside an AnimatedSwitcher widget, so once an answer button is clicked, the next question and answers should be displayed. Unfortunately, the AnimatedSwitcher widget only works when the button is outside its child widget. This is not the behaviour is want, since I want the answer and buttons to both be part of the animation.
Is there a way to do this or possibly a better widget to use? I'd be thankful for your help!
import 'package:flutter/material.dart';
int index = 0;
final widgets = [
QuestionWidget(
question:
Question("What is your favorite color?", ["red", "blue", "green"]),
key: const Key('1')),
QuestionWidget(
question: Question("How do you do today?", ["great", "not so well"]),
key: const Key('2')),
QuestionWidget(
question: Question("Do you like Flutter", ["yes", "no"]),
key: const Key('3')),
];
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Scaffold(
body: Center(
child: SizedBox(
width: size.width * 0.7,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
transitionBuilder: (child, animation) =>
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, -1.0),
end: const Offset(0.0, 0.0))
.animate(animation),
child: FadeTransition(
opacity: animation, child: child)),
child: widgets[index]),
],
))));
}
}
class QuestionWidget extends StatefulWidget {
final Question question;
const QuestionWidget({
required this.question,
Key? key,
}) : super(key: key);
#override
State<QuestionWidget> createState() => _QuestionWidgetState();
}
class _QuestionWidgetState extends State<QuestionWidget> {
#override
Widget build(BuildContext context) {
return Column(children: [
Text(
widget.question.questionText,
style: const TextStyle(
fontSize: 25,
),
),
Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
spacing: 5.0,
children: [
for (var i in widget.question.answers)
ElevatedButton(
child: Text(i.toString()),
onPressed: () {
final isLastIndex = index == widgets.length - 1;
setState(() => index = isLastIndex ? 0 : index + 1);
})
],
)
]);
}
}
class Question {
String questionText;
List<String> answers;
Question(this.questionText, this.answers);
}
Storing mutable state in global variables is not a valid approach in Flutter.
One of the main rules in Flutter developement is: state goes down, events go up.
In your case, it seems that the Test widget should be responsible for defining the index of the current question, so you need to make it a part of its State. The Question widget shouldn't care about what to do when the right answer is selected, it should only know how to detect such a event and who to notify about it.
Putting it all together:
Test should store the current question index
Test should select which Question to display at the given moment
Question should notify Test when the right answer is selected
Test should change the current index in response to the event above.
In your case, notifying about the event can be nothing more than just calling a callback provided in a constructor argument.
In code:
class TestState extends State<Test> {
int _index = 0;
#override
Widget build(BuildContext context) {
...
QuestionWidget(
key: Key(index.toString()),
question: questions[index],
onCorrectAnswer: () => setState(() => index++)),
),
...
}
}
class QuestionWidget extends StatelessWidget {
final void Function() onCorrectAnswer;
#override
Widget build(BuildContext context) {
...
ElevatedButton(
onPressed: () => onCorrectAnswer(),
),
...
}
}
I highly recommend reading Flutter docs' take on state management
With the help of mfkw1's answer, I came up with this solution. I struggled a little with this which was because I did not see that the QuestionWidget was turned into a StatelessWidget.
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
int index = 0;
next() {
final isLastIndex = index == 2;
setState(() => index = isLastIndex ? 0 : index + 1);
}
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
final widgets = [
QuestionWidget(
question: Question(
"What is your favorite color?", ["red", "blue", "green"]),
key: const Key("1"),
onAnswer: () => next()),
QuestionWidget(
question: Question("How do you do today?", ["great", "not so well"]),
key: const Key("2"),
onAnswer: () => next()),
QuestionWidget(
question: Question("Do you like Flutter?", ["yes", "no"]),
key: const Key("3"),
onAnswer: () => next()),
];
var size = MediaQuery.of(context).size;
return Scaffold(
body: Center(
child: SizedBox(
width: size.width * 0.7,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
transitionBuilder: (child, animation) =>
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, -1.0),
end: const Offset(0.0, 0.0))
.animate(animation),
child: FadeTransition(
opacity: animation, child: child)),
child: widgets[index]),
],
))));
}
}
class QuestionWidget extends StatelessWidget {
final Question question;
final Function() onAnswer;
const QuestionWidget({
required this.question,
required this.onAnswer,
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(children: [
Text(
question.questionText,
style: const TextStyle(
fontSize: 25,
),
),
Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
spacing: 5.0,
children: [
for (var i in question.answers)
ElevatedButton(
child: Text(i.toString()),
onPressed: () {
onAnswer();
})
],
)
]);
}
}
class Question {
String questionText;
List<String> answers;
Question(this.questionText, this.answers);
}

Flutter - How to Extract Widget with onPressed setState inside?

I want to Extract a Widget with onPressed setState inside but I get the Message "Reference to an enclosing class method cannot be extracted."
Is there a way to do that?
I would like to divide my code into different widgets so that it remains clear. Here is simplified an example of the code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Calculator(),
);
}
}
class Calculator extends StatefulWidget {
#override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
var myValue = 0;
void calculate() {
myValue = 12;
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: TextButton(
onPressed: () {
setState(() {
calculate();
});
},
child: Text(
'Button 001',
),
),
),
TextOutput(myValue: myValue),
],
),
);
}
}
class TextOutput extends StatelessWidget {
const TextOutput({
Key key,
#required this.myValue,
}) : super(key: key);
final int myValue;
#override
Widget build(BuildContext context) {
return Container(
child: Text(
myValue.toString(),
),
);
}
}
The part I want to extract into a separate widget:
Container(
child: TextButton(
onPressed: () {
setState(() {
calculate();
});
},
child: Text(
'Button 001',
),
),
),
Flutter offers VoidCallback and Function(x) (where x can be a different type) for callback-style events between child and parent widgets.
Simply You can pass Function onPressed; via constructor
Here is your Extracted Container widget:
class ExtractedContainer extends StatelessWidget {
final Function onPressed;
const ExtractedContainer({
Key key, #required this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: () {
onPressed();
},
child: Text(
'Button 001',
),
),
);
}
}
And Here How to use it:
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ExtractedContainer(onPressed: calculate,),
TextOutput(myValue: myValue),
],
),
);
}
Your full code example
import 'package:flutter/material.dart';
class MyApp2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Calculator(),
);
}
}
class Calculator extends StatefulWidget {
#override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
var myValue = 0;
void calculate() {
myValue = 12;
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ExtractedContainer(onPressed: calculate,),
TextOutput(myValue: myValue),
],
),
);
}
}
class ExtractedContainer extends StatelessWidget {
final Function onPressed;
const ExtractedContainer({
Key key, #required this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: () {
onPressed();
},
child: Text(
'Button 001',
),
),
);
}
}
class TextOutput extends StatelessWidget {
const TextOutput({
Key key,
#required this.myValue,
}) : super(key: key);
final int myValue;
#override
Widget build(BuildContext context) {
return Container(
child: Text(
myValue.toString(),
),
);
}
}
Setstate is related to the widget you want to refresh its state. If you extract it to another place, then setState refers to the state of the new widget.
In your case, the setState will only change the state of the container encapsulating your widget which you are trying to extract and its children, it doesn't migrate upward.
Unless, you look for the state of the widget you want, using exact type, and then trigger the state there, but this is overkill, a lot harder, requires more code, than what you currently have.
You can use VoidCallback on extract widget to get onPressed event
class MyContainer extends StatelessWidget {
final VoidCallback onTap;
const MyContainer({
Key? key,
required this.onTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: onTap,
child: Text(
'Button 001',
),
),
);
}
}
And use like
MyContainer(
onTap: () {
print("tapped");
setState(() {
calculate();
});
},
),

How to make ToggleButtons with text under icon

I'm having a bit of a hard time with this idea.
The goal is to have a row of Toggle Icons with text that can overflow onto a second line.
The issue I'm having with the ToggleButtons is that I can't seem to place text underneath each icon.
I currently have a Map<String, Icon> where the string is the text I want below the Icon from that Map.
Is there an easy/possible way to do this?
Yea, you can achieve this by using the Column widget.
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.access_alarm),
SizedBox(height: 5.0,),
Text("Text"),
],
);
Please see the following code to put text under icon in a ToggleButton.
import 'package:flutter/material.dart';
final Color darkBlue = const 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: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Map<String, dynamic> map = {
"one": Icons.ac_unit,
"two": Icons.baby_changing_station,
"three": Icons.cached,
"four": Icons.dangerous,
"five": Icons.east,
"six": Icons.face,
};
List<bool> _isSelected = [];
#override
void initState() {
super.initState();
_isSelected = List.filled(map.length, false);
}
#override
Widget build(BuildContext context) {
return Wrap(
children: [
ToggleButtons(
isSelected: _isSelected,
children: [
...map.entries.map((ele) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(ele.value),
Text(ele.key),
],
);
}).toList(),
],
selectedColor: Colors.blueGrey,
onPressed: (value) {
setState(() {
_isSelected = List.filled(map.length, false);
_isSelected[value] = true;
});
},
),
],
);
}
}
I edited up modifying another answers code from another question to use my map
import 'package:flutter/material.dart';
class WrapToggleIconButtons extends StatefulWidget {
const WrapToggleIconButtons({
#required this.symptomIconDataMap,
#required this.isSelected,
#required this.onPressed,
});
final Map<String, IconData> symptomIconDataMap;
final List<bool> isSelected;
final Function onPressed;
#override
_WrapToggleIconButtonsState createState() => _WrapToggleIconButtonsState();
}
class _WrapToggleIconButtonsState extends State<WrapToggleIconButtons> {
int index;
#override
Widget build(BuildContext context) {
final List<String> symptomsList = widget.symptomIconDataMap.keys.toList();
assert(symptomsList.length == widget.isSelected.length);
index = -1;
return Wrap(
children: symptomsList.map((String symptom) {
index++;
return IconToggleButton(
active: widget.isSelected[index],
iconData: widget.symptomIconDataMap[symptom],
text: symptom,
onTap: widget.onPressed,
index: index,
);
}).toList(),
);
}
}
class IconToggleButton extends StatelessWidget {
const IconToggleButton({
#required this.active,
#required this.iconData,
#required this.text,
#required this.onTap,
#required this.index,
this.width,
this.height,
});
final bool active;
final IconData iconData;
final String text;
final Function onTap;
final double width;
final double height;
final int index;
#override
Widget build(BuildContext context) {
return Container(
width: 80.0,
height: height ?? 60.0,
child: Column(
children: [
InkWell(
child: Icon(
iconData,
color: active ? Theme.of(context).accentColor : Theme.of(context).disabledColor,
),
onTap: () => onTap(index),
),
Wrap(
direction: Axis.horizontal,
children: [
Text(
text,
textAlign: TextAlign.center,
),
],
)
],
),
);
}
}
Flutter: Is there a widget to flex toggle buttons
You can also create a custom widget and use it when you need it.
///CustomTextIcon.dart
import 'package:flutter/material.dart';
class MyIconWithText extends StatelessWidget {
final IconData icon;
final String? text;
const MyIconWithText(this.icon, {Key? key,
this.text
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(icon),
const SizedBox(height: 5.0,),
Text(text ?? ""),
],
);
}
}
and use it as follow:
///Used as a widget
MyIconWithText(Icons.disabled_by_default, text: "Description")