I am working on an attendance application where I assign wages to the workers. I want to store all the wages given to the workers into the database. But the problem is I want to access all the given values on button click. I have no idea how it can be done in flutter. I am a beginner.
I have given all the codes and the image of what output i want.
Image of Emulator
Here is my code...
ATTENDANCE SCREEN
...rest code...
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Upload Patti'),
content: SingleChildScrollView(
child: ListBody(
children: [
TextFormField(
controller: _mainWagesController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Enter Amount",
prefixIcon: Icon(Icons.wallet, color: Colors.blue),
),
),
],
),
),
actions: <Widget>[
ElevatedButton(
onPressed: () {
Navigator.pop(context);
newWages = _mainWagesController.text;
setState(() {});
},
child: const Text("Assign Wages"),
),
],
);
},
);
},
child: const Icon(Icons.check_circle),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.00),
child: Column(children: [
const SizedBox(
height: 20,
),
Center(
child: Text(
"Date : ${DateFormat.yMMMEd().format(DateTime.parse(widget.attendanceDate.toString()))}",
style: const TextStyle(fontSize: 20),
),
),
const SizedBox(
height: 20,
),
FutureBuilder(
future: SupervisorAttendanceServices.getAttendancesDetailsList(
widget.attendanceId),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
var data = snapshot.data['hamal'];
return ListView.builder(
itemCount: data.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return HamalAttendanceWidget(
workerId: data[index]['worker_id'],
name: data[index]['worker_name'],
wages: newWages,
masterAttendanceId: widget.attendanceId,
isPrensent: data[index]
['attendance_worker_presense']
.toString());
});
} else if (snapshot.hasError) {
return const Center(
child: Text("Something went wrong !"),
);
} else {
return const Center(child: LinearProgressIndicator());
}
},
),
]),
),
),
...rest code
widget
Widget build(BuildContext context) {
return Card(
child: Column(children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(
width: 10,
height: 50,
),
const Icon(FeatherIcons.user),
const SizedBox(
width: 20,
),
Text(
widget.name,
style: const TextStyle(fontSize: 18),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
width: 150,
height: 60,
child: TextFormField(
// onChanged: _onChangeHandler,
initialValue: widget.wages.toString(),
decoration: const InputDecoration(
hintText: "Wages",
prefixIcon: Icon(
Icons.wallet,
color: Colors.blue,
)),
)),
],
)
]),
);
}
I suggest you use a StateManager for your application, for example GetX
is a good solution. Create a controller file like the below:
// define this enum outside of class to handle the state of the page for load data
enum AppState { initial, loading, loaded, error, empty, disabled }
Rx<AppState> pageState = AppState.initial.obs;
class AttendanceCntroller extends GetxController{
RxList<dynamic> dataList=RxList<dynamic>();
#override
void onInit() {
//you can write other codes in here to handle data
pageState(AppState.loading);
dataList.value=
SupervisorAttendanceServices.getAttendancesDetailsList(attendanceId);
pageState(AppState.loaded);
super.onInit();
}
}
and in your view(UI) page, handle it in this way:
class AttendanceView extends GetView<AttendanceCntroller>{
#override
Widget body(BuildContext context) {
// TODO: implement body
return Obx( ()=> controller.pageState.value==AppState.loading ? const
Center(child: LinearProgressIndicator()) : ListView.builder(
itemCount: controller.dataList.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return HamalAttendanceWidget(
workerId: controller.dataList['worker_id'],
name: controller.dataList['worker_name'],
wages: newWages,
masterAttendanceId: widget.attendanceId,
isPrensent: controller.dataList[index]
['attendance_worker_presense']
.toString());
})
)
}
}
for more data read the GetX link and read clean architecture with the GetX sample repository of my GitHub it have advanced management of states with GetX with dependency injection handling.
If you want to have prefilled value in TextFormField, you can either use initialValue or controller parameter.
The value of controller parameter will help you to get/update the value of TextFormField.
For controller parameter refer below.
TextEditingController controller = TextEditingController(text: 'This is text will be pre-filled in TextFormField');
...
TextFormField(
controller: controller,
);
Create List or Map of those controllers.
List<TextEditingController> listOfControllers = [ controller1, controlle2,...];
Use for loop through this List on onClick() method of Button.
ElevatedButton(
onPressed: () {
for(var controllerItem in listOfControllers) {
print(controllerItem.text); // the value of TextFormField
}
},
)
I want to implement RefreshIndicator in my Listview.builder but the problem is that when I place RefreshIndicator it's not working. And I search in Google the answer that I find is that place physic:
AlwaysScrollableScroll() in Listview.Builder and when I try it RefreshIndicator worked but Listview.Builder not working and I search in Google the answer that I find is that place physic:
NeverScrollableScroll() in Listview.Builder then My Listview.Builder is working OK but Refresh Indicator not working. What can I do?
I am little bit confused, what I can do: either I place AlwaysScrollableScroll() or NeverScrollable().
Here is my code:
return Scaffold(
body: SafeArea(
child: Padding(
padding: EdgeInsets.all(10),
child: Column(
children: [
FirstRow(
headingText: 'My Appointments',
context: context,
),
SizedBox(
height: 10,
),
Obx(() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AppButtonLarge(
selected: appointmentController.appointmentT ==
'upcomingAppointments' ??
false,
text: 'Upcoming',
onTap: onAppointmentChange),
AppButtonLarge(
selected: appointmentController.appointmentT ==
'pastAppointments' ??
false,
text: 'Past',
onTap: onAppointmentChange),
],
);
}),
SizedBox(
height: 10,
),
Expanded(
child: SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(
children: [
GetX<DoctorAppointmentController>(
builder: (controller) {
// List<Appointment> controller.appointmentList=[];
// allAppointment.forEach((element) {
// if(element!=null){
// controller.appointmentList=controller.appointmentList+element;
// }
// });
// List<Appointment> controller.appointmentList=snapshot.data;
print(controller.appointmentList.length);
return controller.isLoading.value
? AppWidgetsCard.getProgressIndicator()
: controller.appointmentList.length > 0
? RefreshIndicator(
key: refreshKey,
onRefresh: () async{
await Navigator.pushReplacement(context, PageRouteBuilder(pageBuilder: (a,b,c)=>GetAllDrAppointments(),
transitionDuration: Duration(seconds: 3)));
},
child: Obx(()=>ListView.builder(
physics: const NeverScrollableScrollPhysics(),
// reverse: true,
itemCount: controller.appointmentList.length,
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (context, index) {
void goToNext() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
MyAppointments(
appointment: controller
.appointmentList[
index], isDoctor: true),
));
}
if (index ==
controller.appointmentList.length -
1) {
id = controller
.appointmentList[index].id;
return Column(
children: [
TextButton(
onPressed: goToNext,
child: AppWidgetsCard
.getAppointmentCard(
controller.appointmentList[index],
goToNext, isDoctor: true), ),
Obx(
() {
return controller.loadMore.value
? AppWidgetsCard
.getProgressIndicator()
: Container(
height: 40,
width: 200,
child: AppMethodButton(
selected: true,
text: 'Load More',
onTapMethod: () {
print('data');
controller
.fetchMoreAppointments(
id);
}),
);
},
)
],
);
} else {
return TextButton(
onPressed: goToNext,
child: AppWidgetsCard
.getAppointmentCard(
controller
.appointmentList[index],
goToNext, isDoctor: true));
}
},
),
),
)
: AppWidgetsCard.getEmptyCard('Appointment');
},
),
],
),
)),
],
),
)),
bottomNavigationBar: Container(
height: 50,
child: LastRow(
page: 'Appointment',
)),
);'''
About the ScrollPhysics there are different kinds of scrolling behavior. And AlwaysScrollableScroll means that the ListView is able to scroll no matter whether the body size of the ListView is larger than the assigned size. By default, the ListView only scrolls when the size of the body of the ListView is larger than the assigned parent size. So to adopt the RefreshIndicator does not matter with the scroll physics.
To avoid the cache issues of ListView to force the ListView update, you should update the data of the ListView. You would use the Obx wrapper with the ListView and create the list like below:
List<String> data = <String>[].obs;
Obx(()=> data.value.isEmpyty ? SizedBox() : ListView(children: data.value.map((value) => Text(value)).toList())
Here is the related code to help what i mean :
ListView.builder(
itemCount: recentList1.length,
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) {
var recent = recentList1[index];
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => p1Read(contents: recent),
),
);
},
child: Container(
margin: EdgeInsets.symmetric(horizontal: 18.0, vertical: 8.0),
child: pt1Card(contents: recent),
),
);
},
)
I have 3 items inside recentlist1.length. And im trying to set a variable to a number based on which either of the inkwells are clicked, Since there are 3 there will be 3 inkwells in the screen. And im trying to setstate a variable to 1 if the first inkwell is clicked, 2 when the second inkwell is clicked and set the variable to 3 when the third inkwell is clicked. How would i go aout in doing this?
I'm not sure if I understand you right.
Could you not just take the index + 1?
ListView.builder(
itemCount: recentList1.length,
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) {
var recent = recentList1[index];
return InkWell(
onTap: () {
setState((){
YOUR_VARIABLE = index + 1;
});
},
child: Container(
margin: EdgeInsets.symmetric(horizontal: 18.0, vertical: 8.0),
child: pt1Card(contents: recent),
),
);
},
)
How could I add divider to list? I use Flutter for Android. I want to add a divider between each List item and I want to colorize the divider and add styles.
I tried to add new divider(); but I got errors. I also tried return new divider();.
Here is the screen shot of my app:
And here is my code:
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp();
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.purple,
buttonTheme: const ButtonThemeData(
textTheme: ButtonTextTheme.primary,
)
),
home: const MyHomePage(),
);
}
}
class Kitten {
const Kitten({this.name, this.description, this.age, this.imageurl});
final String name;
final String description;
final int age;
final String imageurl;
}
final List<Kitten> _kittens = <Kitten>[
Kitten(
name: "kitchen",
description: "mehraboon",
age: 2,
imageurl:
"https://images.pexels.com/photos/104827/cat-pet-animal-domestic-
104827.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=350",
),
Kitten(
name: "garage",
description: "khashen",
age: 1,
imageurl:
"https://images.pexels.com/photos/4602/jumping-cute-playing-animals.jpg?
auto=compress&cs=tinysrgb&dpr=2&h=350",
),
Kitten(
name: "bedroom",
description: "khar zoor",
age: 5,
imageurl:
"https://images.pexels.com/photos/978555/pexels-photo-978555.jpeg?
auto=compress&cs=tinysrgb&dpr=2&h=350",
),
Kitten(
name: "living room",
description: "chorto",
age: 3,
imageurl:
"https://images.pexels.com/photos/209037/pexels-photo-209037.jpeg?
auto=compress&cs=tinysrgb&dpr=2&h=350",
),
];
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key}) : super(key: key);
Widget _dialogBuilder(BuildContext context, Kitten kitten) {
return SimpleDialog(contentPadding: EdgeInsets.zero, children: [
Image.network(kitten.imageurl, fit: BoxFit.fill),
Padding(
padding: const EdgeInsets.all(16.0),
child:
Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
Text(kitten.name),
Text('${kitten.age}'),
SizedBox(
height: 16.0,
),
Text(kitten.description),
Align(
alignment: Alignment.centerRight,
child: Wrap(
children: [
FlatButton(onPressed: () {}, child: const
Text("noooo!"),color: Colors.red,),
Padding(padding: const EdgeInsets.all(2.0),),
RaisedButton(onPressed: () {}, child: const
Text("yesss!"),color: Colors.green)
],
),
)
]))
]);
}
Widget _listItemBuilder(BuildContext context, int index) {
return new GestureDetector(
onTap: () => showDialog(
context: context,
builder: (context) => _dialogBuilder(context, _kittens[index])),
child:
Container(
padding: EdgeInsets.all( 16.0),
alignment: Alignment.centerLeft,
child: Text(_kittens[index].name,
style: Theme.of(context).textTheme.headline),
),
) ;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Keys"),
centerTitle: true,
),
body: ListView.builder(
itemCount: _kittens.length,
itemExtent: 60.0,
itemBuilder: _listItemBuilder,
),
);
}
}
There are a number of ways to do the same thing. Let me compare them here.
For a short static list
Use ListTile.divideTiles
ListView(
children: ListTile.divideTiles( // <-- ListTile.divideTiles
context: context,
tiles: [
ListTile(
title: Text('Horse'),
),
ListTile(
title: Text('Cow'),
),
ListTile(
title: Text('Camel'),
),
ListTile(
title: Text('Sheep'),
),
ListTile(
title: Text('Goat'),
),
]
).toList(),
)
For a long dynamic list
Use ListView.separated.
ListView.separated(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
title: Text('$index sheep'),
);
},
separatorBuilder: (context, index) {
return Divider();
},
)
This returns two widgets for every item, except for the last item. The separatorBuilder is used to add the divider.
For adding a divider after the last item
Create a custom item widget that uses a Divider or BoxDecoration.
Using Divider
final items = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Column(
children: <Widget>[
ListTile(
title: Text(items[index]),
),
Divider(), // <-- Divider
],
);
},
);
}
Using BoxDecoration
final items = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration( // <-- BoxDecoration
border: Border(bottom: BorderSide()),
),
child: ListTile(
title: Text(items[index]),
),
);
},
);
}
Both Divider and BoxDecoration are customizable as far as the line height and color go. Divider also has an indent option, but you could get a BoxDecoration to do the same thing with some padding.
For more style
Use a Card
final items = ['Horse', 'Cow', 'Camel', 'Sheep', 'Goat'];
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Card( // <-- Card
child: ListTile(
title: Text(items[index]),
),
);
},
);
}
The most correct way is to use ListView.separated
ListView.separated(
itemCount: 25,
separatorBuilder: (BuildContext context, int index) => Divider(height: 1),
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('item $index'),
);
},
);
Put your widget inside container with BoxDecoration as
Container(
child: YourWidgetHere(),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black26))),
);
On the flutter getting started tutorial it is covered, the solution they provide is something like this:
body: ListView.builder(
itemCount: _kittens.length,
itemExtent: 60.0,
itemBuilder: (context, i) {
// Add a one-pixel-high divider widget before each row in theListView.
if (i.isOdd) return new Divider(color: Colors.purple); // notice color is added to style divider
return _listItemBuilder();
},
),
...
That should add the dividers taking into account the odd and even rows to do so.
Also to color the divider pas "color" to the Divider Class:
new Divider(color: Colors.purple);
recently I use this code to set divider:
ListView.separated(
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text("Hello", style: TextStyle(
color: Theme
.of(context)
.primaryColor
),),
);
},
separatorBuilder: (context, index) =>Divider(height: 1, color: Colors.green),
itemCount: 30),
and it works.
For example, I have added my app's screenshot
Check out this issue:
ListView.builder should let clients specify a divider
It makes clear that:
if you need to build your list with dynamic elements, for now you'll have to deal with this issue on your own. I'd recommend in the row widget building, you include a List Divider at the bottom with a column or something, except for the last one (you can test for index == listData.length - 1).
But if, like in the example you show, you already know all the lists data before hand, or you build it without a ListView.builder, then you can and should use the named constructor ListView.divideTiles
following this Just add Divider() :
Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Image.network(video["imageUrl"]),
Container(
height: 6.0,
),
Text(
video["name"],
textScaleFactor: 1.05,
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
),
Divider(
color: Theme.of(context).primaryColor,
)
],
);
Dart 2.3
Another way, especially for generic non-list-view: Using for in a Collection (link) with the ... spread operator
Column(
children: [
for(var i=0; i<4; i+=1)
...[Container(height: 100, width: 100),
Divider()
]])
The question assumes that we have access to material.dart for Android styling (ListTile and Divider). If you want Cupertino styles, we can:
Use a Column view wrapper for the row, and add a Container with height 1.
Column(
children: <Widget>[
row, // A custom Row
Padding(
padding: const EdgeInsets.only(
left: 16, // Adjust separator left padding.
right: 16, // Adjust separator right padding.
),
child: Container(
height: 1,
color: Styles.productRowDivider, // Custom style
),
),
],
);
The Divider is not available in cupertino.dart. We can use the same Container technique with ListView.separated:
ListView.separated(
itemCount: 100,
itemBuilder: (context, index) {
return row;
},
separatorBuilder: (context, index) {
return Container(
height: 1,
color: Styles.productRowDivider, // Custom style
);
},
);
Thats another way usig Container.
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
),
Container(height: 1, color: Colors.grey), //divider
ListTile(
leading: Icon(Icons.logout),
title: Text('Logout'),
),
Create a Container like this
Container(height: 1, color: Colors.grey),
And add with your ListTile like this
ListView.builder(
itemCount: _feed.items.length,
itemBuilder: (BuildContext context, int index) {
final item = _feed.items[index];
return Column(
children: <Widget>[
Container(height: 1, color: Colors.grey), //Container for devider
ListTile( //Your tile item
title: title(item.title),
subtitle: subtitle(item.pubDate),
leading: thumbnail(item.enclosure.url),
trailing: rightIcon(),
contentPadding: EdgeInsets.all(5.0),
onTap: () => openFeed(item.link),
)]);
},
);
Now you can see final output in my screenshot
[1]: https://i.stack.imgur.com/EZuIg.jpg