add icon button in table flutter - flutter

body: Container(
padding: EdgeInsets.all(25),
child: Table(
border: TableBorder.all(),
columnWidths: {
0: FractionColumnWidth(0.14),
1: FractionColumnWidth(0.6),
2: FractionColumnWidth(0.3),
},
children: [
// here to add iconButton
buildRow(['No.','List of Books','Action'], isHeader: true),
buildRow(['1','Harry Potter Philosopher','Action']),
buildRow(['2','Sleeping Beauty','Action']),
buildRow(['3','Beauty and The Beast','Action']),
],
),
),
);
// here List<String>
TableRow buildRow(List<String> cells, {bool isHeader = false}) => TableRow(
children: cells.map((cell) {
final style = TextStyle(
fontWeight: isHeader? FontWeight.bold : FontWeight.normal,
fontSize: 18,
);
return Padding(
padding: const EdgeInsets.all(12),
child: Center(
child: Text(
(cell), //here error
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
),
),
),
);
}).toList(),
);
}
Here is i confused to declare icon button in the parameter buildRow cause it carry String but when i change to Widget it will appear the error at Text(cell). I want to add the iconButton in the third row of the table

Just declare List<Strings> cells to List<Widgets> cells like below code:
Use like this:
buildRow([Text('1'), IconButton(onPressed: (){}, icon: Icon(Icons.edit))], isHeader: true),

Related

Flutter project giving Out of Memory error

Currently building my first app. Getting data from firebase. Purpose is to hopefully get more people to get the COVID vaccine in Kenya.
Explanation of the code below: A user will use the search function to search for a specific county, then all vaccination posts in that county will show up with the relevant data. There are also 2 buttons, yes and no. Users can vote to let other users know if a vaccination post is still administering vaccines or not. Also, when button is pressed, they should get disabled.
I have a list that buttonPressed that when called, x number of "true" is added depending on the number of vaccination posts available. They are linked together using their index's.
Problem is after adding the buttons, I am getting an "Out of Memory" error.
Without the buttons, it runs as intended. Buttons are important because some vaccination posts are still operational while others are not.
Question:
1 - How can I get passed "Out of Memory" error?
Code:
import 'package:colour/colour.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
// import 'package:shared_preferences/shared_preferences.dart';
class VaccineCenterList extends StatefulWidget {
const VaccineCenterList({key}) : super(key: key);
static const String idScreen = "VaccineCenterList";
#override
_VaccineCenterListState createState() => _VaccineCenterListState();
}
class _VaccineCenterListState extends State<VaccineCenterList> {
List<bool> buttonPressed = [];
buttonControls(numOfDrivers) {
print(numOfDrivers);
while (numOfDrivers > 0) {
buttonPressed.add(true);
}
print(buttonPressed);
}
#override
void initState() {
super.initState();
print("I'm in the vaccine list search screen");
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
backgroundColor: Colors.grey[100],
centerTitle: true,
elevation: 0,
iconTheme: const IconThemeData(
color: Colors.black,
),
title: Text(
"Pamoja",
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 35,
),
),
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: SingleChildScrollView(
child: Column(
children: [
Container(
// textfield
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: hospitalCountyEditingController,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.words,
decoration: InputDecoration(
border: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
style: BorderStyle.solid,
width: 1,
),
),
labelText: "Search County",
labelStyle: const TextStyle(
fontSize: 14.0,
color: Colors.blueGrey,
),
hintStyle: GoogleFonts.lexendMega(
color: Colors.grey,
fontSize: 10,
),
),
style: GoogleFonts.lexendMega(
fontSize: 14,
color: Colors.black,
),
),
),
ElevatedButton(
// search button
onPressed: () {
setState(() {
FocusScope.of(context).requestFocus(
FocusNode(),
);
driverList.clear();
if (hospitalCountyEditingController.text == "" ||
hospitalCountyEditingController.text == " ") {
isTrueOrFalse = "False";
} else {
isTrueOrFalse = "True";
}
});
getHospitalDetails();
},
child: Text(
"Search",
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
),
),
),
SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
// height: 50,
// color: Colors.black,
child: Padding(
padding: const EdgeInsets.only(
right: 12.0,
left: 12.0,
bottom: 12.0,
),
child: driverList.isEmpty
? Center(
// child: CircularProgressIndicator(),
child: (isTrueOrFalse == "True")
? const CircularProgressIndicator()
: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Search for one of the counties below",
style:
GoogleFonts.lexendMega()),
),
Text(
"Nairobi, Baringo, Busia, Bomet, Bungoma, Elgeyo Marakwet, Embu, Garissa, Homa Bay, Isiolo, Kajiado, Kakamega, Kericho, Kiambu, Kilifi, Kirinyaga, Kisii, Kisumu, Kitui, Kwale, Laikipia, Lamu, Machakos, Makueni, Mandera, Marsabit, Meru, Migori, Mombasa, Muranga, Nakuru, Nandi, Narok, Nyamira, Nyandarua, Nyeri, Samburu, Siaya County, Taita Taveta, Tana River County, Tharaka Nithi, Trans Nzoia, Turkana, Uasin Gishu, Vihiga, Wajir, West Pokot",
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
),
),
],
),
)
: ListView.builder(
itemCount: driverList.length,
itemBuilder: (context, index) {
buttonControls(driverList.length);
final Hospitals hospitals = driverList[index];
final String hospitalLocaiton =
hospitals.location;
final String hospitalPhone = hospitals.phone;
final String hospitalName = hospitals.name;
positiveCount = hospitals.positiveCount;
negativeCount = hospitals.negativeCount;
final int setpercentage =
calculatePositivePercentage(
positiveCount, negativeCount);
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 0,
child: ExpansionTile(
title: Text(
hospitalName.toUpperCase(),
style: GoogleFonts.lexendMega(),
textAlign: TextAlign.center,
),
children: [
Column(
children: [
Container(
child: (hospitalPhone
.isNotEmpty)
? ElevatedButton(
onPressed: () {
Clipboard.setData(
ClipboardData(
text:
hospitalPhone,
),
);
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.green,
content: Text(
"Number Copied",
textAlign:
TextAlign
.center,
),
),
);
},
child: Text(
hospitalPhone,
textAlign:
TextAlign.center,
style: GoogleFonts
.lexendMega(
fontSize: 13),
),
style: ElevatedButton
.styleFrom(
elevation: 0,
),
)
: const Text(""),
),
const SizedBox(
height: 5,
),
hospitalLocaiton.isNotEmpty
? Container(
padding:
const EdgeInsets.all(
8),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
),
borderRadius:
BorderRadius
.circular(10),
),
child: Text(
hospitalLocaiton,
textAlign:
TextAlign.center,
style: GoogleFonts
.lexendMega(
fontSize: 12,
),
),
)
: Text(
hospitalLocaiton,
textAlign:
TextAlign.center,
style: GoogleFonts
.lexendMega(
fontSize: 12,
),
),
const SizedBox(
height: 10,
),
Text(
"$setpercentage% (percent) of voters say this hospital administer vaccines.",
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontWeight: FontWeight.bold,
fontSize: 12,
color: Colors.deepPurple[400],
),
),
const SizedBox(
height: 10,
),
const Divider(
// thickness: 1,
indent: 20,
endIndent: 20,
color: Colors.black87,
),
const SizedBox(
height: 10,
),
Text(
"Does this Hospital administer Vaccines?\n(To help the public, please vote only if you know.)",
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
// Container(
// child: (positiveCount == 0)
// ? Text("Votes: $positiveCount")
// : Text("Votes: " +
// positiveCount.toString()),
// ),
Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceEvenly,
children: [
ElevatedButton(
onPressed:
buttonPressed[index]
? () {
positiveIncrement(
hospitalName,
index);
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.redAccent,
content:
Text(
"Voted",
textAlign:
TextAlign.center,
),
),
);
}
: null,
child: Text(
"Yes",
style: GoogleFonts
.lexendMega(),
),
style: ElevatedButton
.styleFrom(
primary:
Colour("#87D68D"),
),
),
ElevatedButton(
onPressed:
buttonPressed[index]
? () {
negativeIncrement(
hospitalName,
index);
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
backgroundColor:
Colors.redAccent,
content:
Text(
"Voted",
textAlign:
TextAlign.center,
),
),
);
}
: null,
child: Text(
"No",
style: GoogleFonts
.lexendMega(),
),
style: ElevatedButton
.styleFrom(
primary:
Colour("#E3655B"),
),
),
],
),
// const SizedBox(
// height: 10,
// ),
// Text(
// "Total No. of Votes: ",
// style:
// GoogleFonts.lexendMega(
// fontSize: 12),
// ),
const SizedBox(
height: 10,
),
Text(
"1 - To vote, tap once\n2 - To Undo vote, tap and hold",
style:
GoogleFonts.lexendMega(
fontSize: 12,
),
textAlign: TextAlign.start,
),
const SizedBox(
height: 10,
),
],
),
],
),
],
),
),
);
},
),
),
),
// SizedBox(height: 40),
],
),
),
],
),
),
),
);
}
}
class Hospitals {
final String name;
final String phone;
final String location;
// final String county;
final int positiveCount;
final int negativeCount;
// final int intPercentage;
// final int totalVotes;
Hospitals({
required this.name,
required this.phone,
required this.location,
// required this.county,
required this.positiveCount,
required this.negativeCount,
// required this.intPercentage,
// required this.totalVotes,
});
static Hospitals fromJson(Map<String, dynamic> json) {
return Hospitals(
name: json['HospitalName'],
phone: json['HospitalPhone'],
// county: json['county'],
location: json['HospitalAddres'],
positiveCount: json['poitiveCount'],
negativeCount: json['negativeCount'],
// intPercentage: json['intPercentage'],
// totalVotes: json['totalVotes']
);
}
}
buttonControls(numOfDrivers) {
print(numOfDrivers);
while (numOfDrivers > 0) {
buttonPressed.add(true);
}
print(buttonPressed);
}
numOfDrivers reference doesn't change over time, because it's a function parameter. Whenever you call buttonControls with numOfDrivers > 0, you get OutOfMemory.
Ask another question. It's a general problem, not related to OutOfMemory statement in title.

How to remove searchable dropdown default padding in flutter?

Hello this is my flutter widget SearchableDropdown, and it is wrapped using a container just for highlighting the border for understanding how much space the widget have been taken.
I want to reduce the padding/space of the SearchableDropdown widget around the text, and make the UI like this. How to do that?
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new Text(
'You are here',
style: GoogleFonts.poppins(
color: HexColor("#B8B8B8"), fontSize: 10),
textAlign: TextAlign.start,
),
new Container(
decoration: new BoxDecoration(
border: Border.all(color: Colors.red),
),
child: _searchableDropDown(context, providerData),
)
],
),
Widget _searchableDropDown(BuildContext context, HomePageProviderData data) {
return new SearchableDropdown.single(
hint: new Text(
data.currentCity,
style: GoogleFonts.poppins(
textStyle: TextStyle(
color: Color(0xFF373539),
fontSize: 16,
fontWeight: FontWeight.w600),
),
),
underline: SizedBox(),
displayClearIcon: false,
items: data.listCity.map((item) {
//
}).toList(),
onChanged: (String value) {
//
},
);
}
try use wrapping your dropdown inside SizedBox() like this :
SizedBox(
height: 20,
child: _searchableDropDown(context, providerData),
);
result:

Flutter dialog always refreshing on select an item of auto complete text view in opened dialog

I am struggling to select an item from auto complete text view which is placed under the dialog. When I search something it is showing me suggestions but item not keeps selected when I going to tap on one item because I noticed that whole dialog is refreshing on item click of auto complete text view.
I have create a separate screen for this dialog also but still same
issue is coming.
class AssetEditDialog extends StatefulWidget {
#override
State createState() => new AssetEditDialogState();
}
class AssetEditDialogState extends State<AssetEditDialog> {
final dbHelper = DatabaseHelper.instance;
TextEditingController roomController = new TextEditingController();
final FocusNode _roomFocusNode = new FocusNode();
#override
Widget build(BuildContext context) {
roomController.text =
Global.scanAssetResult.assetRoom.isEmpty && Global.scanAssetResult.assetRoom == null ? Global.notAvailable : Global.scanAssetResult.assetRoom;
AutoCompleteTextField searchTextField;
GlobalKey<AutoCompleteTextFieldState<String>> key = new GlobalKey();
return Dialog(
child: new Container(
padding: EdgeInsets.all(10),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Asset Number",
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 12,
),
),
Container(
margin: EdgeInsets.fromLTRB(0, 5, 0, 0),
),
Text(
Global.scanAssetResult.assetNo,
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.black,
fontSize: 12,
),
),
Container(
margin: EdgeInsets.fromLTRB(0, 5, 0, 0),
),
Text(
"Asset Serial Number",
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 12,
),
),
Container(
margin: EdgeInsets.fromLTRB(0, 5, 0, 0),
),
Text(
Global.scanAssetResult.assetSerialNo,
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.black,
fontSize: 12,
),
),
Container(
margin: EdgeInsets.fromLTRB(0, 5, 0, 0),
),
Text(
"Asset Sector",
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 12,
),
),
searchTextField = AutoCompleteTextField<String>(
key: key,
suggestions: Global.sectorList,
style: new TextStyle(color: Colors.black, fontSize: 16.0),
decoration: new InputDecoration(
contentPadding: EdgeInsets.fromLTRB(5.0, 5.0, 5.0, 5.0),
hintText: 'Search here',
hintStyle: TextStyle(color: Colors.black)),
itemFilter: (item, query) {
return item.toLowerCase().startsWith(query.toLowerCase());
},
itemSorter: (a, b) {
return a.toLowerCase().compareTo(b.toLowerCase());
},
clearOnSubmit: false,
itemSubmitted: (item) {
setState(() {
try {
searchTextField.textField.controller.text = item;
return;
} on Exception catch (exception) {
Global.writeErrorLog(true, "Autocomplete text view ", exception.toString());
}
});
},
itemBuilder: (context, item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
item,
style: TextStyle(fontSize: 16.0),
),
SizedBox(
width: 10.0,
),
Padding(
padding: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 20.0),
),
],
);
},
),
],
),
),
);
}
Here is screenshot :
Please give a proper solution to achieve it.
Thanks.
I got an answer. Just look below code:
Just remove below lines :
setState(() { //Remove this line
try {
searchTextField.textField.controller.text = item;
return;
} on Exception catch (exception) {
Global.writeErrorLog(true, "Autocomplete text view ", exception.toString());
}
}); ////Remove this line also
Because, Flutter call the build method again when we call setState((){}); method.
Enjoy.

How to make a widget available after a selection in dropdown?

I want to create a card after a user makes a selection in drop down how to achieve this in flutter. The UI model is given below.
The first card is like a permanent one but the second card should appear after if there is any change in the dropdown button.
The lower card should be scrollable and the size should be dynamic like a listview. if the Key and data increases the value should increase.
The Code I have used for creating the app bar and the 1st card is here.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 75,
title: Center(
child: Text(
'Flutter App',
style: GoogleFonts.lato(
textStyle:
TextStyle(fontWeight: FontWeight.bold, fontSize: 26)),
),
),
),
body: ListView(children: [
Column(
children: [
Container(
height: 250,
child: Column(children: [
Card(
child: Column(
children: [
Row(children: [
Padding(
padding: EdgeInsets.only(left: 30, top: 15),
child: Text(
'Text here',
style: GoogleFonts.poppins(
textStyle: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 37,
)),
textAlign: TextAlign.left,
),
),
]),
Padding(
padding: EdgeInsets.only(top: 30),
child: Text(
'Some text here',
style: GoogleFonts.lato(
textStyle: TextStyle(fontSize: 18)),
),
),
Padding(
padding: EdgeInsets.only(top: 30),
child: DropdownButton(
items: markets
.map<DropdownMenuItem<String>>((String val) {
return DropdownMenuItem<String>(
value: val, child: Text(val));
}).toList(),
onChanged: (sto) {
setState(() {
_mySelection = sto;
});
retrievedata.getPrice(_mySelection);
},
value: _mySelection,
hint: Text('Hint text here'),
),
),
],
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 5,
margin: EdgeInsets.all(10),
),
]),
),
],
),
]),
);
}
You can wrap the Card that should appear after dropDownChanges to Visibility widget.
Add this variable
bool _isVisible = false;
Make changes to DropdownButton
DropdownButton(
...
onChanged: (sto) {
setState(() {
_mySelection = sto;
_isVisible = true;
});
retrievedata.getPrice(_mySelection);
},
...
),
Wrap the Card with Visiblity
Visibility (
visible: _isVisible,
child: Card(
child: ....
),
),
If you want the card to be always visible and enable interaction only after the DropdownButton changes, wrap the card to IgnorePointer instead of visibility.
You can achieve this by having an additional state that is responsible for visibility of second card. Something like this:
final visible = false;
#override
Widget build(BuildContext context) {
return
...
onChanged: (sto) {
setState(() {
_mySelection = sto;
visible = true;
});
retrievedata.getPrice(_mySelection);
},
...
And later on we can make the second card visible based on this value:
visible ? SecondCard(
...
) : SizedBox.shrink()
This ensures that nothing is shown until visible is set to true

How to center the Title of a ListTile in Flutter

I have been trying again today to center the title of a Flutter ListTile. Over the past few days I have spent an hour or two Googling and trying things then loosing my cool and giving up.
I am just learning Flutter and love the concept but can find no video training courses (Lynda.com, uDemy.com etc). I have read through the relevant documentation but cannot get rid of all the red lines that appear when I try to apply them to my code.
There must be logic in the syntax but after 2 weeks I have not worked it out yet.
Back to the problem, I have tried
List<Widget> list = <Widget>[
new ListTile(
new child: Center (
title:
new Text('Title 1',
style: new TextStyle(
fontWeight: FontWeight.w500,
color: Colors.deepOrangeAccent,
fontSize: 25.0)),
)
),
];
List<Widget> list = <Widget>[
new ListTile(
title:
new child: Center (
new Text('Title 2',
style: new TextStyle(
fontWeight: FontWeight.w500,
color: Colors.deepOrangeAccent,
fontSize: 25.0)),
)
),
];
List<Widget> list = <Widget>[
new ListTile(
child: Center
title: (
new Text('Title 3',
style: new TextStyle(
fontWeight: FontWeight.w500,
color: Colors.deepOrangeAccent,
fontSize: 25.0)),
)
),
];
List<Widget> list = <Widget>[
new ListTile(
title: Center
new Text('Title 4',
style: new TextStyle(
fontWeight: FontWeight.w500,
color: Colors.deepOrangeAccent,
fontSize: 25.0)),
)
),
];
Please help me with this problem and also where to find a video course on Flutter?
On the upside, if this continues I will no longer be grey, I will be bald instead.
I thought I worked it out when I added 'textAlign: TextAlign.center,' to the text object. There were no red lines but the text was still left aligned.
I am not sure what have you tried, but you in order to center the title of the ListTile you can use a center widget like you did in your code, or wrap your text within a Row widget and set mainAxisAlignment: MainAxisAlignment.center.
Using Center widget:
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("ListTile Example"),),
body: new ListView(
children: new List.generate(7, (int index) {
return new ListTile(
title: new Center(child: new Text("Centered Title#$index",
style: new TextStyle(
fontWeight: FontWeight.w500, fontSize: 25.0),)),
subtitle: new Text("My title is centered"),
);
}),
),
);
}
Using Row widget:
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("ListTile Example"),),
body: new ListView(
children: new List.generate(7, (int index) {
return new ListTile(
title: new Row(children: <Widget>[new Text("Centered Title#$index",
style: new TextStyle(
fontWeight: FontWeight.w500, fontSize: 25.0),)
], mainAxisAlignment: MainAxisAlignment.center,),
subtitle: new Text("My title is centered"),
);
}),
),
);
}
However, your problem is not about centering the title, it is about you are trying to insert too big of a Text inside a small area, that is why you are getting the red lines, so one solution is choose a smaller fontSize, a better solution is to get rid of ListTile and build your own custom widget, since a ListTile is
A single fixed-height row that typically contains some text as well as
a leading or trailing icon.
So it should not be used if you are using bigger widgets.
This is simple example of how to create a custom widget that resembles ListTile, but is more flexible and customizable when dealing with larger items:
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("ListTile Example"),),
body: new ListView(
children: new List.generate(7, (int index) {
return new Container(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 20.0),
child: new Column(
children: <Widget>[
new Align (child: new Text("Centered Title $index",
style: new TextStyle(fontSize: 40.0),), //so big text
alignment: FractionalOffset.topLeft,),
new Divider(color: Colors.blue,),
new Align (child: new Text("Subtitle $index"),
alignment: FractionalOffset.topLeft,),
new Divider(color: Colors.blue,),
new Align (child: new Text("More stuff $index"),
alignment: FractionalOffset.topLeft,),
new Row(mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[ //add some actions, icons...etc
new FlatButton(onPressed: () {}, child: new Text("EDIT")),
new FlatButton(onPressed: () {},
child: new Text("DELETE",
style: new TextStyle(color: Colors.redAccent),))
],),
],
),
);
}),
)
);
}
You can change the alignment of the text by using textAlign
Use this to center the Title of a ListTile:
ListTile(title: Text('YOUR TEXT', textAlign: TextAlign.center));
Here is my example of a three-row tile:
class ThreeRowTile extends StatelessWidget {
final Widget title;
final Widget detail;
final String utility1;
final String utility1Help;
final String utility2Help;
final String utility2;
final Icon icon;
final String cell;
final String home;
final String office;
final String email;
final VoidCallback cellTapped;
final VoidCallback cellLongPressed;
final VoidCallback iconTapped;
ThreeRowTile({
this.title,
this.icon,
this.detail,
this.utility1,
this.utility1Help,
this.utility2,
this.utility2Help,
this.cellTapped,
this.home,
this.email,
this.cell,
this.office,
this.cellLongPressed,
this.iconTapped,
});
#override
Widget build(BuildContext context) {
List<Widget> buildChildren() {
List<Widget> builder = [];
if (cell.isNotEmpty && !cell.toString().contains("--")) {
builder.add(ListTile(
leading: const Icon(Icons.phone),
title: Text(
'Cell',
textScaleFactor: globals.textScaleFactor,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
cell.toString().length > 0 ? cell : "No Number Found",
textScaleFactor: globals.textScaleFactor,
),
onTap: cell.toString().contains("--")
? null
: () {
globals.Utility.makePhoneCall(context, cell);
},
));
}
if (office.isNotEmpty && !office.toString().contains("--")) {
builder.add(ListTile(
leading: const Icon(Icons.work),
title: Text(
'Office',
textScaleFactor: globals.textScaleFactor,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
office.toString().length > 0 ? office : "No Number Found",
textScaleFactor: globals.textScaleFactor,
),
onTap: office.toString().contains("--")
? null
: () {
globals.Utility.makePhoneCall(context, office);
},
));
}
if (home.isNotEmpty && !home.toString().contains("--")) {
builder.add(ListTile(
leading: const Icon(Icons.home),
title: Text(
'Home',
textScaleFactor: globals.textScaleFactor,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
home.toString().length > 0 ? home : "No Number Found",
textScaleFactor: globals.textScaleFactor,
),
onTap: home.toString().contains("--")
? null
: () {
globals.Utility.makePhoneCall(context, home);
},
));
}
if (email.isNotEmpty && !email.contains('No Email Address')) {
builder.add(ListTile(
leading: const Icon(Icons.email),
title: Text(
'Email',
textScaleFactor: globals.textScaleFactor,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
email.toString().length > 0 ? email : "No Email Found",
textScaleFactor: globals.textScaleFactor,
),
onTap: email.toString().isEmpty
? null
: () {
globals.Utility.sendEmail(context, email);
},
));
}
if (builder.isEmpty) {
builder.add(
ListTile(
leading: const Icon(Icons.info),
title: Text(
'No Contact Information Found',
textScaleFactor: globals.textScaleFactor,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
);
}
return builder;
}
String _utility1 =
utility1 == null || utility1.contains("1-1-1800") ? "" : utility1;
String _utility2 =
utility2 == null || utility2.contains("1-1-1800") ? "" : utility2;
var rowCard = Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey[300]))),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
child: new Column(
children: <Widget>[
Row(
children: <Widget>[
Align(
child: IconButton(
icon: icon,
onPressed: iconTapped,
),
alignment: FractionalOffset.centerLeft,
),
Expanded(
child: Column(
children: <Widget>[
new Align(
child: title, //so big text
alignment: FractionalOffset.topLeft,
),
// new Divider(),
new Align(
child: detail,
alignment: FractionalOffset.topLeft,
),
// new Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: Container(
margin: const EdgeInsets.all(3.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(
color: _utility1.length > 1
? Colors.grey
: Colors.transparent)),
child: Tooltip(
message:
utility1Help == null ? "" : utility1Help,
child: Text(
_utility1,
maxLines: 1,
textAlign: TextAlign.center,
textScaleFactor: globals.textScaleFactor,
),
),
),
),
Expanded(
child: Container(
margin: const EdgeInsets.all(3.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(
color: _utility2.length > 1
? Colors.grey
: Colors.transparent)),
child: Tooltip(
message: utility2 == null ? "" : utility2,
child: Text(
_utility2,
maxLines: 1,
textAlign: TextAlign.center,
textScaleFactor: globals.textScaleFactor,
),
),
),
),
],
),
],
),
),
Align(
child: IconButton(
icon: Icon(Icons.arrow_drop_down),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
child: Padding(
padding: EdgeInsets.only(bottom: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: buildChildren()),
),
));
});
},
),
alignment: FractionalOffset.centerRight,
),
],
),
],
),
),
// color: globals.isDarkTheme ? Colors.black45 : Colors.white,
);
return (rowCard);
}
}
And it can be used like this:
ThreeRowTile(
icon: Icon(Icons.person),
title: _contacts?.items[index]?.lastName.toString().isEmpty &&
_contacts?.items[index]?.firstName.toString().isEmpty
? null
: Text(
(_contacts?.items[index]?.lastName ?? "") +
", " +
(_contacts?.items[index]?.firstName ?? ""),
textScaleFactor: globals.textScaleFactor,
),
detail: Text(
_contacts?.items[index]?.lastActivity,
textScaleFactor: globals.textScaleFactor,
),
utility1: _contacts?.items[index]?.dateCreated,
utility1Help: 'Date Created',
utility2: _contacts?.items[index]?.dateModified,
utility2Help: "Date Modified",
cell: _contacts?.items[index]?.cell,
home: _contacts?.items[index]?.home,
office: _contacts?.items[index]?.office,
email: _contacts?.items[index]?.email,
cellTapped: () {
globals.contactID = _contacts?.items[index]?.contactID;
Navigator.of(context).pushNamed("/contact_details").then((value) {
if (globals.infoChanged) {
_getData("", false).then((newitems) {
setState(() {
_contacts = newitems;
});
});
}
});
},
);