Flutter ListView.builder() item click change UI data? - flutter

I want to increase the quantity when '+' icon se clicked and decrease the quantity when '-' icon is clicked in the ListView.builder(). But my code changes quantity of all listview items whichever icon I clicked. I'm new to Flutter and Dart. I want to change the data of particular row when user taps either '+' or '-' icon of that particular row.
Please help me to resolve my issue.
Here is my code -:
import 'package:flutter/material.dart';
import 'package:flutter_testing/InkWellGesture.dart';
class Cart extends StatefulWidget {
Cart({Key key}) : super(key: key);
#override
_CartState createState() => _CartState();
}
class _CartState extends State<Cart> {
int qty = 1;
int items = 2;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Cart'),
),
body: Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(
left: 3,
),
height: 60,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
elevation: 3,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 3, top: 7, right: 6),
width: 13,
height: 15,
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.green),
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Deliver to NAME address line 1...',
style: TextStyle(fontSize: 15)),
Text('click here to change address',
style: TextStyle(
fontSize: 12, color: Colors.grey)),
],
),
],
),
),
Icon(Icons.keyboard_arrow_right),
],
),
),
),
Expanded(
child: ListView.builder(
itemCount: items,
itemBuilder: (ctx, itemIndex) {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
child: Container(
height: 65,
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
child: Row(
children: <Widget>[
Container(
width: 65,
height: 65,
decoration: BoxDecoration(
border:
Border.all(color: Colors.grey, width: 1),
borderRadius:
BorderRadius.all(Radius.circular(10))),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding:
const EdgeInsets.only(left: 10, right: 7),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Item Name',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold)),
Text(
'\u{20B9} 9,999',
style: TextStyle(fontSize: 18),
),
],
),
),
Padding(
padding: const EdgeInsets.only(right: 4),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
inkWellGesture(
() {
setState(() {
qty += 1;
});
},
child: Icon(
Icons.add_circle,
color: Colors.green,
size: 25,
),
),
Text(
qty > 0 ? qty.toString() : '1',
style: TextStyle(fontSize: 16),
),
inkWellGesture(
() {
setState(() {
qty -= 1;
});
},
child: Icon(
Icons.remove_circle,
color: Colors.red,
size: 25,
),
)
],
),
),
Expanded(
flex: 2,
child: Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Icon(
Icons.delete_forever,
color: Colors.red,
size: 25,
),
],
),
)
],
),
),
],
),
),
],
),
),
);
}),
),
Container(
height: 200,
padding: const EdgeInsets.only(top: 15, left: 15, right: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
obscureText: true,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Promo Code',
)),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Shipping'),
Text('Offer'),
Text('Tax'),
Text('Sub Total'),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(' \u{20B9} 80'),
Text('- \u{20B9} 100'),
Text(' \u{20B9} 1,799'),
Text(' \u{20B9} 8,200')
],
),
],
),
),
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
child: FlatButton(
child: Text('PROCEED TO \u{20B9} 10,019',
style: TextStyle(fontSize: 20)),
onPressed: () {},
color: Colors.green,
textColor: Colors.white,
))),
],
),
);
}
Here is the screenshot -:

Create an array of quantity having the same size that your items. Associate each item qty to the corresponding quantity array index.
int items = 2;
List<int> qties = [];
#override
void initState () {
for (int i = 0; i < items; ++ i) qties.add(1);
}
// ...
inkWellGesture(
() {
setState(() {
qties[itemIndex] += 1;
});
},
child: Icon(
Icons.add_circle,
color: Colors.green,
size: 25,
),
),
Text(
qties[itemIndex] > 0 ? qties[itemIndex].toString() : '1',
style: TextStyle(fontSize: 16),
),
inkWellGesture(
() {
setState(() {
qties[itemIndex] -= 1;
});
},
child: Icon(
Icons.remove_circle,
color: Colors.red,
size: 25,
),
),

All the values change because they all refer to the same qty variable. Each of your list item should have its own value. A way to do this would be to create a class containing all the data of your item.
class CardItem {
String name;
int qty;
String price;
// I've defined some default values but it could be anything else
CardItem({#required this.name, this.qty = 1, this.price = "9,999"});
}
Then you could generate a list of CardItem to build your ListView.
List<CardItem> _listItems = [];
int items = 2;
#override
void initState() {
super.initState();
for (int i = 0; i < items; i++) _listItems.add(CardItem(name: "Item Name $i", qty: 2));
}
// ...
// For the item name and price
Text(
_listItems[itemIndex].name,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
'\u{20B9} ${_listItems[itemIndex].price}',
style: TextStyle(fontSize: 18),
),
// To add or remove
inkWellGesture(
() {
setState(() => _listItems[itemIndex].qty += 1);
},
child: Icon(
Icons.add_circle,
color: Colors.green,
size: 25,
),
),
Text(
_listItems[itemIndex].qty > 0 ? _listItems[itemIndex].qty.toString() : '1',
style: TextStyle(fontSize: 16),
),
inkWellGesture(
() {
setState(() => _listItems[itemIndex].qty -= 1);
},
child: Icon(
Icons.remove_circle,
color: Colors.red,
size: 25,
),
),

Make sure you're getting the item's quantity by its index (itemBuilder: (ctx, itemIndex)). Try this:
Expanded(
child: ListView.builder(
itemCount: items,
itemBuilder: (ctx, itemIndex) {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
child: Container(
height: 65,
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
child: Row(
children: <Widget>[
Container(
width: 65,
height: 65,
decoration: BoxDecoration(
border:
Border.all(color: Colors.grey, width: 1),
borderRadius:
BorderRadius.all(Radius.circular(10))),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding:
const EdgeInsets.only(left: 10, right: 7),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(items[itemIndex].name,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold)),
Text(
'\u{20B9} ${items[itemIndex].amount}',
style: TextStyle(fontSize: 18),
),
],
),
),
Padding(
padding: const EdgeInsets.only(right: 4),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
inkWellGesture(
() {
setState(() {
items[itemIndex].quantity += 1;
});
},
child: Icon(
Icons.add_circle,
color: Colors.green,
size: 25,
),
),
Text(
items[itemIndex].quantity > 0 ? items[itemIndex].quantity.toString() : '1',
style: TextStyle(fontSize: 16),
),
inkWellGesture(
() {
setState(() {
items[itemIndex].quantity -= 1;
});
},
child: Icon(
Icons.remove_circle,
color: Colors.red,
size: 25,
),
)
],
),
),
Expanded(
flex: 2,
child: Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Icon(
Icons.delete_forever,
color: Colors.red,
size: 25,
),
],
),
)
],
),
),
],
),
),
],
),
),
);
}),
),

Related

Flutter SliverAppBar add widget to collapsed part

I'm currently developing a flutter mobile app by using sliver appbar and I want to add some widget to collapsed app bar.and also make background color to gradient. when I tried to add by using leading property it creates overflow and also the widget displays in the flexspacebar.
The above image is before scroll.
and this one is after scroll and I want to add some widget in the center of the blue part.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rehove/Widgets/sliver_card.dart';
import '../Widgets/action_button.dart';
class UserScreen extends StatelessWidget {
const UserScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
TextTheme _textTheme = Theme.of(context).textTheme;
return
AnnotatedRegion<SystemUiOverlayStyle>(
value: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light
),
child: Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
collapsedHeight: 320,
pinned: true,
leadingWidth: 200,
leading: Padding(
padding: EdgeInsets.only(left:32),
child: GestureDetector(
onTap:()=>{
Navigator.pop(context)
},
child: Row(
children: [
Icon(Icons.arrow_back_ios),
Text('Back',style: _textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w500,
fontSize: 16
),)
],
),
),
),
expandedHeight: 450,
flexibleSpace: FlexibleSpaceBar(
background: Stack(
children: [
Image.asset('assets/images/user.png',
width: double.infinity,
height: double.infinity,
fit: BoxFit.cover,
),
Align(
alignment:Alignment.bottomCenter,
child: Container(
height: 102,
width: double.infinity,
color:Color(0xffD9D9D9).withOpacity(0.6),
child:Padding(
padding:const EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Liya Dereje',style: _textTheme.bodyLarge?.copyWith(
color: Color(0xffffffff),
fontWeight: FontWeight.w500,
fontSize: 20
),),
Text('LiyaDereje2#gmail.com',style: _textTheme.bodyLarge?.copyWith(
color: Color(0xfff7f7f7),
fontWeight: FontWeight.w500,
fontSize: 12
),)
],
),
ActionButton(label: 'Edit Profile',
height: 38,
width: 20,
onPressed: () { },)
],
),
)
),
)
]
),
),
),
SliverToBoxAdapter(
child:Column(children: [
const SizedBox(height: 40,),
Row(
children: [
const Expanded(child: Divider(thickness: 1,)),
Text('Setting',style: _textTheme.bodySmall?.copyWith(
fontSize: 14,
fontWeight: FontWeight.w400
),),
const Expanded(child: Divider(thickness: 1,)),
],
),
const SizedBox(height: 16,),
SliverCard(icon: Icons.notifications_outlined,title: 'Notification',amount: '4',),
const SizedBox(height: 10,),
SliverCard(icon: Icons.donut_small,title: 'Reports',amount: '4',),
const SizedBox(height: 10,),
SliverCard(icon: Icons.email_outlined,title: 'Email',amount: '5',),
const SizedBox(height: 10,),
SliverCard(icon: Icons.description_outlined,title: 'Terms of',amount: '3',),
const SizedBox(height: 10,),
SliverCard(icon: Icons.accessibility_new_rounded,title: 'Accessibility',amount: '4',),
const SizedBox(height: 10,),
SliverCard(icon: Icons.logout,title: 'Logout',amount: '4',),
const SizedBox(height: 10,),
SliverCard(icon: Icons.email_outlined,title: 'Email',amount: '5',),
const SizedBox(height: 10,),
SliverCard(icon: Icons.description_outlined,title: 'Terms of',amount: '3',),
const SizedBox(height: 10,),
SliverCard(icon: Icons.accessibility_new_rounded,title: 'Accessibility',amount: '4',),
const SizedBox(height: 10,),
],
)
)
],
),
)
);
}
}
Step 1:
First declare the varibale
bool lastStatus = true;
ScrollController? _nestedScrollController;
Step 2:
void _scrollListener() {
if (_isShrink != lastStatus) {
setState(() {
lastStatus = _isShrink;
});
}
}
bool get _isShrink {
return _nestedScrollController != null &&
_nestedScrollController!.hasClients &&
_nestedScrollController!.offset > (30.h - kToolbarHeight);
}
put above method inside the class
Step 3:
#override
void dispose() {
_nestedScrollController?.removeListener(_scrollListener);
_nestedScrollController?.dispose();
super.dispose();
}
#override
void initState() {
_nestedScrollController =
ScrollController(initialScrollOffset: 33.h - kToolbarHeight)
..addListener(_scrollListener);
}
Put the above method inside the init and dispose
Step 4:
Scaffold(
resizeToAvoidBottomInset: false,
body: NestedScrollView(
controller: _nestedScrollController,
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
TransitionsAppsBar(
isShrink: _isShrink,
….
…
),
];
},
body: child…
Step 5:
Use require code inside the below class
class TransitionsAppsBar extends StatelessWidget {
final bool isShrink;
final VoidCallback? onBackTap;
final VoidCallback? onInfoTap;
final VoidCallback? onTap;
final VoidCallback onAlertTap;
final GroupDetailsDTO? groupInfo;
final bool isOverDue;
const TransitionsAppsBar({
Key? key,
this.isShrink = true,
this.onBackTap,
this.onInfoTap,
this.groupInfo,
this.onTap,
this.isOverDue = false,
required this.onAlertTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocBuilder<GroupBloc, GroupState>(
builder: (context, state) {
return SliverAppBar(
elevation: 2,
backgroundColor: AppTheme.secondaryColor,
pinned: true,
collapsedHeight: kToolbarHeight + (isOverDue ? 25 : 0),
centerTitle: true,
titleSpacing: 0,
leadingWidth: 21.w,
automaticallyImplyLeading: false,
bottom: !isOverDue
? null
: PreferredSize(
child: GestureDetector(
onTap: onAlertTap,
child: Container(
color: AppTheme.primaryColor_100,
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
Assets.icOverdue,
height: 20,
width: 20,
color: AppTheme.whiteColor,
),
const SizedBox(width: 4),
Text(
StringConstants.groupIsInactive,
style: Theme.of(context)
.textTheme
.caption!
.copyWith(color: AppTheme.whiteColor),
),
const SizedBox(width: 4),
Text(
StringConstants.learnMore,
style:
Theme.of(context).textTheme.caption!.copyWith(
color: AppTheme.whiteColor,
decoration: TextDecoration.underline,
),
),
],
),
),
),
preferredSize: const Size.fromHeight(0),
),
title: GestureDetector(
onTap: onTap,
child: Visibility(
visible: isShrink,
child: Container(
color: Colors.transparent,
width: 100.w,
height: kToolbarHeight,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Text(
groupInfo?.name ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style:
Theme.of(context).textTheme.caption!.copyWith(
fontSize: 14,
color: AppTheme.whiteColor,
overflow: TextOverflow.ellipsis,
),
),
),
if (groupInfo?.isOverdue ?? false) ...[
const SizedBox(width: 8),
GestureDetector(
onTap: onAlertTap,
child: Image.asset(
Assets.icOverdue,
height: 20,
width: 20,
),
),
]
],
),
if ((groupInfo?.id ?? 0) != 0)
Text(
"${(groupInfo?.memberDetails.length ?? 0).toString()} ${StringConstants.loopers}",
style: Theme.of(context)
.textTheme
.caption!
.copyWith(fontSize: 14, color: AppTheme.whiteColor),
)
else
Container(),
],
),
),
),
),
leading: Stack(
alignment: Alignment.centerLeft,
children: [
Container(
margin: EdgeInsets.only(left: 5.h),
child: Visibility(
visible: isShrink,
child: ((groupInfo?.id ?? 0) != 0)
? ProfilePic(
imageUrl: groupInfo?.image,
name: (groupInfo?.name.length ?? 0) <= 3 ||
groupInfo!.isIndividualGroup
? groupInfo?.name
: groupInfo?.name.characters.take(3).toString(),
picType: groupInfo!.isIndividualGroup
? StringConstants.systemGroup
: StringConstants.group,
)
: Container(),
),
),
BackButtonWidget(onBackTap: onBackTap),
],
),
expandedHeight: 30.h,
flexibleSpace: FlexibleSpaceBar(
background: Center(
child: Visibility(
visible: !isShrink,
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 12.h),
child: ((groupInfo?.id ?? 0) != 0)
? ProfilePic(
imageUrl: groupInfo?.image,
name: (groupInfo?.name.length ?? 0) <= 3 ||
groupInfo!.isIndividualGroup
? groupInfo?.name
: groupInfo?.name.characters.take(3).toString(),
picType: groupInfo!.isIndividualGroup
? StringConstants.systemGroup
: StringConstants.group,
sizeMultiplier: 2.5.h,
)
: Container(),
),
SizedBox(height: 2.h),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
child: Padding(
padding: const EdgeInsets.only(left: 12),
child: Text(
groupInfo?.name ?? "",
maxLines: 2,
style:
Theme.of(context).textTheme.subtitle2!.copyWith(
color: AppTheme.whiteColor,
overflow: TextOverflow.ellipsis,
),
),
),
),
if (groupInfo?.isOverdue ?? false)
Padding(
padding: const EdgeInsets.only(right: 12, left: 8),
child: GestureDetector(
onTap: onAlertTap,
child: Image.asset(
Assets.icOverdue,
height: 20,
width: 20,
),
),
)
else
const SizedBox(width: 12),
],
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text(
(groupInfo?.memberDetails ?? [])
.getMemberNames(groupInfo?.adminId ?? 0),
style: Theme.of(context)
.textTheme
.caption
?.copyWith(color: AppTheme.whiteColor),
),
),
],
),
),
)),
actions: [
Visibility(
visible: !groupInfo!.isIndividualGroup &&
!state.isFetchingGroupDetails,
child: GestureDetector(
onTap: onInfoTap,
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: Image.asset(
Assets.icInfoGroup,
height: 25,
width: 25,
color: AppTheme.whiteColor,
),
),
),
)
],
);
},
);
}
}
Add another Stack that wraps your FlexibleSpaceBar and the widget you want in the middle when collapsed. Try this:
flexibleSpace: Stack(
children: [
Positioned.fill(
child: Align(
alignment: Alignment.center,
child: Text('I\'m in the center'),
),
),
FlexibleSpaceBar(
background: Stack(children: [
Image.asset(
'assets/images/user.png',
width: double.infinity,
height: double.infinity,
fit: BoxFit.cover,
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 102,
width: double.infinity,
color: Color(0xffD9D9D9).withOpacity(0.6),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'Liya Dereje',
style: _textTheme.bodyLarge?.copyWith(
color: Color(0xffffffff),
fontWeight: FontWeight.w500,
fontSize: 20),
),
Text(
'LiyaDereje2#gmail.com',
style: _textTheme.bodyLarge?.copyWith(
color: Color(0xfff7f7f7),
fontWeight: FontWeight.w500,
fontSize: 12),
)
],
),
ActionButton(
label: 'Edit Profile',
height: 38,
width: 20,
onPressed: () {},
)
],
),
)),
)
]),
),
],
),

Flutter using ChangeNotifierProvider.value

i have Provider model:
class TerminalDataModel with ChangeNotifier{
List<Item> _itemMenu = listItems;
final List<Order> _ordersList = orders;
Order? _currentOrder;
Order? get currentOrder => _currentOrder;
List<Order> get ordersList => _ordersList;
void createOrder() {
_currentOrder = Order(
user: currentUser?.name,
number: 1,
orderStatus: OrderStatus.opened,
time: DateTime.now());
_ordersList.add(_currentOrder!);
notifyListeners();
}
void changeOrder(Order order){
}
}
and two pages: 1. terminal page: on this page I can view my selected order and can change it or change status(paid or for example closed)
class OrderList extends StatelessWidget {
TerminalDataModel terminalDataModel = TerminalDataModel();
OrderList({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: ChangeNotifierProvider<TerminalDataModel>.value(
value: terminalDataModel,
child: OrdersTableView(),
));
}
}
class OrdersTableView extends StatelessWidget {
List<GlobalKey> _key = List.generate(3, (v) => new GlobalKey());
double yPosition = 170;
var provider;
OrdersTableView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
provider = Provider.of<TerminalDataModel>(context, listen: true);
GlobalKey key = GlobalKey();
return Column(
children: [
Stack(
children: [
Container(
height: 40,
color: Styles.appBarColor,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Container(
height: double.infinity,
width: 50,
color: Styles.blackColor,
child: IconButton(
onPressed: () {
Navigator.pushNamed(context, '/terminal');
},
icon: const Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
)),
Row(
children: [
Text(currentUser?.name ?? '',
style: const TextStyle(
color: Colors.white, fontSize: 18)),
const Icon(
Icons.lock,
color: Colors.white,
),
],
),
],
),
),
SizedBox(
height: 40,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Center(
child: Text('Orders',
style: TextStyle(color: Colors.white, fontSize: 18))),
],
),
),
],
),
Stack(children: [
Container(
height: 50,
width: MediaQuery.of(context).size.width,
color: Styles.blackColor,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
ElevatedButton(
onPressed: () {
Provider.of<TerminalDataModel>(context, listen: false)
.createOrder();
},
child: const Text("New order",
style: TextStyle(color: Colors.white, fontSize: 18)),
),
const SizedBox(
width: 25,
),
TextButton(
key: _key[0],
onPressed: () {},
child: const Text('All Status',
style: const TextStyle(
color: Colors.white, fontSize: 18))),
const SizedBox(
width: 25,
),
TextButton(
key: _key[1],
onPressed: () {},
child: const Text('Wait pay',
style: TextStyle(color: Colors.white, fontSize: 18))),
const SizedBox(
width: 25,
),
TextButton(
key: _key[2],
onPressed: () {},
child: const Text('Payed',
style: TextStyle(color: Colors.white, fontSize: 18))),
],
),
),
),
Positioned(
bottom: -22,
left: yPosition,
child: const Icon(
Icons.arrow_drop_up,
size: 50,
color: Colors.white,
))
]),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: SizedBox(
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Expanded(
flex: 3,
child: Text('Open',
style: TextStyle(color: Colors.black, fontSize: 18))),
Expanded(
flex: 5,
child: Text('Order',
style: TextStyle(color: Colors.black, fontSize: 18))),
Expanded(
flex: 3,
child: Text('Status',
style: TextStyle(color: Colors.black, fontSize: 18))),
Expanded(
flex: 1,
child: Text('Sum',
style: TextStyle(color: Colors.black, fontSize: 18))),
],
),
),
),
const Divider(),
ordersList(provider.ordersList, context),
],
);
}
double getYPositionOfWidget(
GlobalKey key,
) {
RenderBox box = key.currentContext?.findRenderObject() as RenderBox;
Offset position = box.localToGlobal(Offset.zero); //this is global position
double y = position.dy;
return y;
}
Widget ordersList(List<Order> orderList, BuildContext context) {
Column ordersTable = Column(
children: <Widget>[],
);
for (int i = 0; i <= orderList.length - 1; i++) {
ordersTable.children.add(
GestureDetector(
onTap: () {
//Navigator.pushNamed(context, '/terminal',arguments: {'model': provider });
Navigator.push(context, MaterialPageRoute(builder: (contex) {
return Provider<TerminalDataModel>.value(
value: provider, child: PosTerminal());
}));
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: SizedBox(
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${orderList[i].time!.hour}:${orderList[i].time!.minute}",
style: const TextStyle(
color: Colors.black, fontSize: 18)),
Text(getTimeAgo(orderList[i].time ?? DateTime.now()),
style: const TextStyle(
color: Colors.black, fontSize: 13))
],
)),
const Expanded(
flex: 5,
child: Text('Order',
style: TextStyle(color: Colors.black, fontSize: 18))),
const Expanded(
flex: 3,
child: Text('Status',
style: TextStyle(color: Colors.black, fontSize: 18))),
const Expanded(
flex: 1,
child: Text('Sum',
style: TextStyle(color: Colors.black, fontSize: 18))),
],
),
),
),
),
);
ordersTable.children.add(const Divider());
}
return ordersTable;
}
String getTimeAgo(DateTime dateTime) {
String timeAgo = '';
if (dateTime.hour < DateTime.now().hour) {
timeAgo += "${DateTime.now().hour - dateTime.hour} hours, ";
}
if (dateTime.minute < DateTime.now().minute) {
timeAgo += "${DateTime.now().minute - dateTime.minute} minutes";
}
return timeAgo;
}
}
and 2. order_detale page: there I show a list of orders and can create a new order
class PosTerminal extends StatelessWidget {
PosTerminal({Key? key, }) : super(key: key);
#override
Widget build(BuildContext context) {
print(Provider.of<TerminalDataModel>(context,listen: false).ordersList);
return Scaffold(
backgroundColor: Styles.backgroundColor,
body: ChangeNotifierProvider(
create: (context) => TerminalDataModel(),
child: const PosBody(),
)
);
}
}
class PosBody extends StatelessWidget {
const PosBody({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
double sizeW = MediaQuery.of(context).size.width;
double appBarH = 35;
return Column(
children: [
SizedBox(
width: sizeW,
height: appBarH,
child: Stack(children: [
SizedBox(
width: sizeW,
height: appBarH,
child: Container(
color: Styles.appBarColor,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
ElevatedButton.icon(
onPressed: () {
Navigator.pushNamed(context, '/orders');
},
icon: const Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
label: Text(AppLocalizations.of(context)!.orders,
style: const TextStyle(
color: Colors.white, fontSize: 18)),
style: ElevatedButton.styleFrom(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
/* Please add this to avoid padding */
elevation: 0,
primary: Colors.transparent,
),
),
SizedBox(
height: appBarH - 3,
width: 100,
child: ElevatedButton(
onPressed: () {},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Styles.backgroundColor),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4),
topRight: Radius.circular(4),
))),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
elevation: MaterialStateProperty.all(0),
),
child: Text(
AppLocalizations.of(context)!.order,
style: const TextStyle(
color: Colors.black, fontSize: 18),
),
),
),
],
),
Row(
children: [
const Text("Сергей",
style:
TextStyle(color: Colors.white, fontSize: 18)),
const SizedBox(
width: 5,
),
const Icon(
Icons.lock,
color: Colors.white,
),
ElevatedButton.icon(
onPressed: () {
final action = CupertinoActionSheet(
actions: <Widget>[
CupertinoActionSheetAction(
child: const Text(
"Admin panel",
style:
TextStyle(color: Styles.appBarColor),
),
onPressed: () {
Navigator.pushNamed(
context, '/adminPanel');
},
),
CupertinoActionSheetAction(
child: const Text("Settings",
style: TextStyle(
color: Styles.appBarColor)),
onPressed: () {},
)
],
cancelButton: CupertinoActionSheetAction(
child: const Text(
"Cancel",
style: TextStyle(color: Colors.red),
),
onPressed: () {
Navigator.pop(context);
},
),
);
showCupertinoModalPopup(
context: context,
builder: (context) => action);
},
icon: const Icon(Icons.menu),
label: const Text(""),
style: ElevatedButton.styleFrom(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
/* Please add this to avoid padding */
elevation: 0,
primary: Colors.transparent,
),
),
],
)
],
),
),
),
SizedBox(
width: sizeW,
height: appBarH,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text("Чек № 2323",
style: TextStyle(color: Colors.white, fontSize: 18)),
],
),
),
]),
),
SizedBox(
height: MediaQuery.of(context).size.height - appBarH,
child: Row(
children: [
Expanded(
flex: 2,
child: Container(
color: Styles.backgroundColor,
child: Column(
children: [
const SizedBox(
height: 25,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Expanded(flex: 4, child: Text("Наименование")),
Expanded(flex: 1, child: Text("Кол-во")),
Expanded(flex: 1, child: Text("Цена")),
Expanded(flex: 1, child: Text("Итого")),
],
),
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 15.0),
child: Divider(
height: 1,
color: Colors.black12,
),
),
SizedBox(
height: MediaQuery.of(context).size.height -
appBarH -
200,
child: Container(),
),
const Divider(
height: 1,
color: Colors.black12,
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 25, vertical: 10),
child: Column(
children: [
Row(
children: const [
Text("Итого"),
],
),
const SizedBox(
height: 10,
),
Row(
children: const [
Text("К оплате"),
],
),
Padding(
padding:
const EdgeInsets.symmetric(vertical: 15),
child: SizedBox(
height: 30,
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.green,
),
onPressed: () {},
child: const Text("Pay")),
),
)
],
)),
],
),
),
),
Expanded(
flex: 4,
child: Container(
color: Colors.white,
),
),
],
),
)
],
);
}
}
On the model, I save my orders and when I tap on the order I want to pass an object to the 2nd-page, update it and when I pop my 2nd-page list of orders should be updated. How I can do it?

How can bind items details from the listview in flutter?

I need help on how to achive binding items from the list view into other widget. For example, I have a listview of Products to be sold, when a sale person click any product from the list, it should be added on top of the screen with it price, then more product can be added each time a sale person press new product from the listview. I have already tried different ways to achieve this. This is a sample of the screen I want to achieve.
This is what I have achieved so far
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class NewSale extends StatefulWidget {
const NewSale({Key? key}) : super(key: key);
#override
_NewSaleState createState() => _NewSaleState();
}
class _NewSaleState extends State<NewSale> {
TextEditingController searchingInput = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.green),
backgroundColor: Colors.white,
elevation: 0.0,
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(top: 8.0),
child: Text(
"Sales",
style: TextStyle(color: Color(0xff444444), fontSize: 19),
),
),
Text(
"Manage Sales",
style: TextStyle(color: Color(0xffa1a1a1), fontSize: 13),
),
],
),
actions: [
Builder(
builder: (context) => IconButton(
icon: Image.asset("assets/images/icons/sync_products.png"),
onPressed: () => {},
)),
],
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: const Icon(
Icons.arrow_back,
color: Colors.black,
size: 40, // Changing Drawer Icon Size
),
onPressed: () {
Navigator.pop(context);
},
);
},
),
),
bottomNavigationBar: new Container(
height: 70.0,
padding: EdgeInsets.only(top: 10),
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Flexible(
child: Container(
width: MediaQuery.of(context).size.width * 0.4,
child: Column(
children: [
MaterialButton(
elevation: 0.00,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Color(0xffFA7659),
width: 1,
style: BorderStyle.solid),
borderRadius: BorderRadius.circular(3)),
textColor: Colors.white,
color: Color(0xffFA7659),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(14.0),
child: Text('CLEAR',
style: TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.w300)),
),
],
),
],
),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
),
Flexible(
child: Container(
width: MediaQuery.of(context).size.width * 0.4,
child: Column(
children: [
MaterialButton(
elevation: 0.00,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Color(0xff78BD42),
width: 1,
style: BorderStyle.solid),
borderRadius: BorderRadius.circular(3)),
textColor: Colors.white,
color: Color(0xff78BD42),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(14.0),
child: Text(
'CONFIRM',
style: TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.w300),
),
),
],
),
],
),
onPressed: () {},
),
],
),
),
),
],
),
),
body: SafeArea(
child: Container(
color: Colors.red,
height: MediaQuery.of(context).size.height * 1,
width: MediaQuery.of(context).size.width * 1,
child: Column(
children: [
Flexible(
child: Container(
height: MediaQuery.of(context).size.height * .5,
width: MediaQuery.of(context).size.width * 1,
color: Colors.grey,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'==== Product Cart ====',
style: TextStyle(color: Color(0xff5c5c5c)),
textAlign: TextAlign.center,
),
),
),
),
Flexible(
child: Container(
height: MediaQuery.of(context).size.height * .5,
width: MediaQuery.of(context).size.width * 1,
color: Colors.white,
child: Column(
children: [
Row(
children: [
Column(
children: [
Container(
padding: EdgeInsets.fromLTRB(15, 10, 0, 0),
child: MaterialButton(
elevation: 0.00,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Color(0xff828282),
width: 1,
style: BorderStyle.solid),
borderRadius: BorderRadius.circular(3)),
textColor: Colors.white,
color: Color(0xff828282),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Row(
children: [
Image.asset(
'assets/images/icons/scan.png',
width: 20,
height: 20,
),
Padding(
padding:
const EdgeInsets.all(14.0),
child: Text('SCAN',
style: TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight:
FontWeight.w300)),
),
],
),
],
),
],
),
onPressed: () {},
),
),
],
),
Flexible(
child: Column(
children: [productSearchingField()],
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Flexible(
child: Container(
width: MediaQuery.of(context).size.width * 0.6,
padding: EdgeInsets.fromLTRB(15, 7, 15, 0),
child: Column(
children: [
MaterialButton(
elevation: 0.00,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Color(0xff78BD42),
width: 1,
style: BorderStyle.solid),
borderRadius: BorderRadius.circular(3)),
textColor: Colors.white,
color: Color(0xff78BD42),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Row(
children: [
Column(
children: [Icon(Icons.add)],
),
Column(
children: [
Padding(
padding:
const EdgeInsets.only(
top: 14.0,
bottom: 14.0),
child: Text(
'ADD NEW PRODUCT',
style: TextStyle(
fontSize: 14,
color: Colors.white,
fontWeight:
FontWeight
.w300),
),
),
],
),
],
),
],
),
],
),
onPressed: () {},
),
],
),
),
),
],
),
Flexible(
child: Container(
child: ListView.builder(
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Image.asset(
'assets/images/icons/brand-identity.png',
width: 50,
height: 50,
),
trailing: Text(
"100,000",
style: TextStyle(
color: Colors.green, fontSize: 15),
),
title: Text("This is item $index"),
subtitle: Text('Electronics'),
);
}),
),
),
],
),
),
),
],
),
),
),
);
}
productSearchingField() {
return Container(
padding: EdgeInsets.fromLTRB(15, 10, 15, 0),
height: 60,
child: TextFormField(
controller: searchingInput,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Search Product or Barcode',
prefixIcon: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.search,
color: Colors.black54,
)),
),
),
);
}
}
Here i manage to do this using the below code hope it will work for you
class _DummyDesignState extends State<DummyDesign> {
List<String> ShoppingItems = ['Ball', 'Clet', 'JoyStick'];
List<String> PurchasedItem = [];
#override
Widget build(BuildContext context) {
print('List length is ${ShoppingItems.length}');
print('List length is ${PurchasedItem.length}');
return Scaffold(
appBar: AppBar(
title: Text('Hello'),
),
body: PurchasedItem.isEmpty
? Center(
child: Container(
height: MediaQuery.of(context).size.height * 0.2,
child: ListView.builder(
itemCount: ShoppingItems.length,
itemBuilder: (context, index) {
return ListTile(
onTap: (){
PurchasedItem.add(ShoppingItems[index]);
setState(() {
});
},
leading: Icon(Icons.list),
title: Text(
ShoppingItems[index],
style: TextStyle(color: Colors.green, fontSize: 15),
));
}),
),
)
: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height * 0.4,
child: ListView.builder(
itemCount: PurchasedItem.length,
itemBuilder: (context, index) {
return Text(PurchasedItem[index]);
}),
),
Container(
height: MediaQuery.of(context).size.height * 0.4,
child: ListView.builder(
itemCount: ShoppingItems.length,
itemBuilder: (context, index) {
return ListTile(
onTap: (){
PurchasedItem.add(ShoppingItems[index]);
setState(() {
});
},
leading: Icon(Icons.list),
title: Text(
ShoppingItems[index],
style: TextStyle(color: Colors.green, fontSize: 15),
));
}),
),
],
),
),
));
}
}

I tried to make reusable widget but "The method '[]' was called on null. Receiver: null"

H3ll0, everyone. I'm new to this. I use Flutter on Android Studio. I wanna ask a question about reusable widget and its correlation to the API
I tried to make this and I tried to called it under a Container with width of MediaQuery size width
class VarianPenjualan extends StatefulWidget {
final productDetail;
const VarianPenjualan({Key? key, this.productDetail}) : super(key: key);
#override
_VarianPenjualanState createState() => _VarianPenjualanState();
}
class _VarianPenjualanState extends State<VarianPenjualan> {
List arrList = [];
var listData = [];
bool isChecked = false;
int _counter = 0;
void initState() {
super.initState();
getProductDetailData(widget.productDetail['id']);
getProduct();
}
getProductDetailData(id) async {
var respon = await ApiService().getProductDetail({"id": id});
if (respon['status'] == 200) {
if (!this.mounted) return;
setState(() {
listData.addAll([respon['data']]);
});
}
}
getProduct() async {
var respon = await ApiService().getProduct({"limit": 6, "page": 1});
if (respon['status'] == 200) {
if (!this.mounted) return;
setState(() {
arrList.addAll(respon['data']['productAsgrosList']);
});
}
}
_incrementCounter() {
setState(() {
_counter++;
});
}
_decrementCounter() {
setState(() {
if (_counter > 0) {
_counter--;
}
});
}
#override
Widget build (BuildContext context) {
return Row(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Checkbox(
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
),
), // CheckBox
Expanded(
flex: 2,
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
Text(
"Kemasan",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Color(0xff000000)),
),
Padding(
padding: const EdgeInsets.only(
top: 5.0),
child:
Text("${(listData[0]['packaging'][0]['kemasan'])}"),
)
],
),
), // Kemasan
Expanded(
flex: 2,
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
Text(
"Harga",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Color(0xff000000)),
),
Padding(
padding: const EdgeInsets.only(
top: 5.0),
child: Text("${GlobalFunctions().rupiah(listData[0]['packaging'][0]['price'])}"),
)
],
),
), // Harga
Expanded(
flex: 1,
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
Text(
"Stok",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Color(0xff000000)),
),
Padding(
padding: const EdgeInsets.only(
top: 5.0),
child: Text("${(listData[0]['packaging'][0]['stock'])}"),
)
],
),
), // Stok
Expanded(
flex: 3,
child: Column(
children: [
Container(
width: 120,
height: 30,
decoration: BoxDecoration(
color: Color(0xFF31708F),
borderRadius:
BorderRadius.circular(3),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: InkWell(
onTap: () {
_decrementCounter();
},
child: Container(
alignment:
Alignment.center,
// padding: EdgeInsets.only(
// right: 10),
child: Icon(
Icons.remove,
color: Color(
0xffFFFFFF),
),
),
),
), // Minus
Expanded(
flex: 1,
child: Text(
'$_counter',
textAlign:
TextAlign.center,
style: TextStyle(
color:
Colors.white),
),
),
// Quantity Number
Expanded(
flex: 1,
child: InkWell(
onTap: () {
_incrementCounter();
},
child: Container(
alignment:
Alignment.center,
// padding: EdgeInsets.only(
// right: 10),
child: Icon(
Icons.add,
color: Color(
0xffFFFFFF),
),
),
),
), // Add
],
),
), // Counter
Container(
margin: EdgeInsets.only(top: 7),
padding: EdgeInsets.fromLTRB(
7, 4, 7, 4),
width: 120,
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(
width: 0.5,
color:
Color(0xff31708F)),
borderRadius:
BorderRadius.all(
Radius.circular(
2))),
child: Text("${GlobalFunctions().rupiah(listData[0]['packaging'][0]['price'] * _counter)}"),
), // Total Harga
],
),
), // Quantity Counter
SizedBox(
width: 10,
),
],
); // varian 1
}
}
but " The method '[]' was called on null. Receiver: null. Tried calling: " appeared
I tried to understand the answers from the similiar question, but i can't understand it. Can you guys help me?
You need to add loading widget since the listData fetch all response and then build the widget:
class _VarianPenjualanState extends State<VarianPenjualan> {
List arrList = [];
var listData = [];
bool isChecked = false;
int _counter = 0;
bool isLoaded = false;
void initState() {
super.initState();
getProductDetailData(widget.productDetail['id']);
getProduct();
}
getProductDetailData(id) async {
var respon = await ApiService().getProductDetail({"id": id});
if (respon['status'] == 200) {
if (!this.mounted) return;
setState(() {
listData.addAll([respon['data']]);
isLoaded = true;
});
}
}
getProduct() async {
var respon = await ApiService().getProduct({"limit": 6, "page": 1});
if (respon['status'] == 200) {
if (!this.mounted) return;
setState(() {
arrList.addAll(respon['data']['productAsgrosList']);
});
}
}
_incrementCounter() {
setState(() {
_counter++;
});
}
_decrementCounter() {
setState(() {
if (_counter > 0) {
_counter--;
}
});
}
#override
Widget build(BuildContext context) {
return isLoaded
? listData.length != 0
? Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Checkbox(
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
),
), // CheckBox
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
"Kemasan",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Color(0xff000000)),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Text(
"${(listData[0]['packaging'][0]['kemasan'])}"),
)
],
),
), // Kemasan
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
"Harga",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Color(0xff000000)),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Text(
"${GlobalFunctions().rupiah(listData[0]['packaging'][0]['price'])}"),
)
],
),
), // Harga
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
"Stok",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Color(0xff000000)),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child:
Text("${(listData[0]['packaging'][0]['stock'])}"),
)
],
),
), // Stok
Expanded(
flex: 3,
child: Column(
children: [
Container(
width: 120,
height: 30,
decoration: BoxDecoration(
color: Color(0xFF31708F),
borderRadius: BorderRadius.circular(3),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: InkWell(
onTap: () {
_decrementCounter();
},
child: Container(
alignment: Alignment.center,
// padding: EdgeInsets.only(
// right: 10),
child: Icon(
Icons.remove,
color: Color(0xffFFFFFF),
),
),
),
), // Minus
Expanded(
flex: 1,
child: Text(
'$_counter',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
// Quantity Number
Expanded(
flex: 1,
child: InkWell(
onTap: () {
_incrementCounter();
},
child: Container(
alignment: Alignment.center,
// padding: EdgeInsets.only(
// right: 10),
child: Icon(
Icons.add,
color: Color(0xffFFFFFF),
),
),
),
), // Add
],
),
), // Counter
Container(
margin: EdgeInsets.only(top: 7),
padding: EdgeInsets.fromLTRB(7, 4, 7, 4),
width: 120,
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(
width: 0.5, color: Color(0xff31708F)),
borderRadius:
BorderRadius.all(Radius.circular(2))),
child: Text(
"${GlobalFunctions().rupiah(listData[0]['packaging'][0]['price'] * _counter)}"),
), // Total Harga
],
),
), // Quantity Counter
SizedBox(
width: 10,
),
],
)
: Center(
child: Text('No Data'),
)
: CircularProgressIndicator(); // varian 1
}
}

SetState Not updating value of parameter Flutter ?? I want to Toggle between grid but setstate only showing the grid view. ?? How can i update state o

when I click on IconButton photo_size_select it's not updating the text form _setPostToggle(String toggletype). it's only showing grid view text when I clicked on both icon button? why set state is not working? I/flutter (27517): gridView I/flutter (27517): gridView SetState Not updating value of parameter Flutter? I want to Toggle between grid but setstate only showing the grid view. How can i update state o
class Profile extends StatefulWidget {
final String? profileId;
Profile({required this.profileId});
#override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
final String? currentUserId = currentUser?.id;
String postViewStyle = 'gridView';
bool isLoading = false;
int postCount = 0;
List<Post> posts = [];
#override
void initState() {
super.initState();
getProfilePosts();
}
getProfilePosts() async {
setState(() {
isLoading = true;
});
QuerySnapshot snapshot = await postRef
.doc(widget.profileId)
.collection('userPosts')
.orderBy('timestamp', descending: true)
.get();
setState(() {
isLoading = false;
postCount = snapshot.docs.length;
posts = snapshot.docs
.map((doc) => Post.fromDocument(doc))
.toList(growable: true);
});
print(posts.toList().toString());
}
editProfile() {
Navigator.push(
this.context,
MaterialPageRoute(
builder: (context) => EditProfilePageWidget(
currentUserId: currentUserId,
)),
);
}
//build button on users condtion
buildButton({required String text, required Function function}) {
return Padding(
padding: EdgeInsets.fromLTRB(15, 20, 15, 0),
child: TextButton(
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
side: BorderSide(
color: Colors.grey.shade900,
width: 1,
)),
)),
onPressed: () async {
await function();
},
child: Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Lato',
fontSize: 18,
),
),
),
);
}
// Button for Profile header
buildProfileButton() {
// View our own profile and follow button
bool isProfileOwner = currentUserId == widget.profileId;
if (isProfileOwner) {
return buildButton(text: "Edit Profile", function: editProfile);
}
}
buildProfilePost() {
if (isLoading) {
return CircularProgressIndicator();
} else if (postViewStyle == 'gridView') {
List<GridTile> gridTiles = [];
posts.forEach((element) {
gridTiles.add(
GridTile(
child: PostGrid(post: element),
),
);
});
return GridView.count(
padding: EdgeInsets.zero,
crossAxisCount: 3,
childAspectRatio: 1,
crossAxisSpacing: 2.5,
mainAxisSpacing: 2.5,
shrinkWrap: true,
primary: false,
// physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
children: gridTiles,
);
} else if (postViewStyle == "listView") {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: posts,
);
}
}
_setPostToggle(String toggleType) {
setState(() {
toggleType = this.postViewStyle;
});
}
buildToogleView() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
onPressed: () {
_setPostToggle("gridView");
print(postViewStyle);
},
icon: Icon(
Icons.grid_view_rounded,
size: 25,
),
color: Colors.deepPurple.shade500,
),
IconButton(
onPressed: () {
_setPostToggle("listView");
print(postViewStyle);
},
icon: Icon(
Icons.photo_size_select_actual_outlined,
size: 25,
),
color: Colors.deepPurple.shade500,
)
],
);
}
override
Widget build(BuildContext context) {
return FutureBuilder(
future: usersRef.doc(widget.profileId).get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgressBar();
}
Users user = Users.fromDocument(snapshot.data);
return Scaffold(
appBar: header(context, titleText: "Knot me"),
body: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsets.fromLTRB(8, 8, 0, 0),
child: Icon(
Icons.alternate_email_rounded,
color: Colors.grey.shade600,
size: 17,
),
),
Padding(
padding: EdgeInsets.fromLTRB(1, 8, 0, 0),
child: Text(
user.username,
style: GoogleFonts.aBeeZee(
fontSize: 19.0,
fontWeight: FontWeight.bold,
color: Colors.grey.shade800),
),
),
],
),
],
),
),
Expanded(
child: ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
scrollDirection: Axis.vertical,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: EdgeInsets.fromLTRB(12, 0, 0, 1),
child: Container(
width: 100,
height: 100,
child: Stack(
children: [
Align(
alignment: Alignment(-0.4, -0.02),
child: Padding(
padding:
EdgeInsets.fromLTRB(1, 0, 0, 0),
child: Container(
width: 100,
height: 96,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image(
image: CachedNetworkImageProvider(
user.photoUrl),
),
),
),
),
Align(
alignment: Alignment(1, 1),
child: Container(
width: 27,
height: 27,
decoration: BoxDecoration(
color: Color(0xFF1062AE),
shape: BoxShape.circle,
),
child: Icon(
CupertinoIcons.add_circled,
color: Colors.white,
size: 24,
),
),
)
],
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 15, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Column(
mainAxisSize: MainAxisSize.max,
children: [
Text(
"$postCount".toString(),
style: TextStyle(
fontFamily: 'Lato',
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
Padding(
padding:
EdgeInsets.fromLTRB(0, 3, 0, 0),
child: Text(
'Posts',
style: TextStyle(
fontFamily: 'Lato',
fontSize: 17,
),
),
)
],
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'179',
style: TextStyle(
fontFamily: 'Lato',
fontSize: 17,
),
),
Padding(
padding:
EdgeInsets.fromLTRB(0, 3, 0, 0),
child: Text(
'Followers',
style: TextStyle(
fontFamily: 'Lato',
fontSize: 17,
// color: Colors.white,
),
),
)
],
),
),
Column(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'144',
style: TextStyle(
fontFamily: 'Lato',
fontSize: 17,
),
),
Padding(
padding:
EdgeInsets.fromLTRB(0, 3, 0, 0),
child: Text(
'Followers',
style: TextStyle(
fontFamily: 'Lato',
fontSize: 17,
),
),
)
],
)
],
),
)
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 16, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: MediaQuery.of(context).size.width * 0.55,
decoration: BoxDecoration(
color: Colors.transparent,
),
child: Align(
alignment: Alignment(-1, 0),
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
user.displayName,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily: 'Lato',
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Padding(
padding:
EdgeInsets.fromLTRB(0, 3, 0, 0),
child: Text(
user.bio,
style: TextStyle(
fontFamily: 'Lato',
fontSize: 15,
),
),
)
],
),
),
),
)
],
),
),
buildProfileButton(),
Divider(
height: 0.0,
),
buildToogleView(),
Divider(
height: 0.0,
),
buildProfilePost(),
],
),
)
],
),
),
);
},
);
}
}
Build Page