Shopping Cart Counter not updating value when pressed, no Error is shown for the matter - flutter

I have a small code for a shopping cart counter in my app, when running the app it does not update upon pressing the add or remove button (+ & - icons), although I assigned the functions for both of them, no errors are shown as to why this is happening...
This is the code for the counter:
import 'package:flutter/material.dart';
class CartCounter extends StatefulWidget {
#override
_CartCounterState createState() => _CartCounterState();
}
class _CartCounterState extends State<CartCounter> {
int numOfItems = 0;
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
buildOutlineButton(
icon: Icons.remove,
press: () {
if (numOfItems > 0) {
setState(() {
numOfItems--;
});
}
},
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: kDefaultPaddin / 2),
child: Text(
// if our item is less then 10 then it shows 01 02 like that
numOfItems.toString().padLeft(2, "0"),
style: Theme.of(context).textTheme.headline6,
),
),
buildOutlineButton(
icon: Icons.add,
press: () {
if (numOfItems < 10) {
setState(() {
numOfItems++;
});
}
}),
],
);
}
SizedBox buildOutlineButton(
{required IconData icon, required Function press}) {
return SizedBox(
width: 40,
height: 32,
child: OutlinedButton(
style: OutlinedButton.styleFrom(
padding: EdgeInsets.zero,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(13.0)),
),
onPressed: press(),
child: Icon(icon),
),
);
}
}
And this is the code where I call the Cart Counter class, it also has a rating bar that works perfectly fine:
class CounterWithRateBar extends StatefulWidget {
#override
_CounterWithRateBarState createState() => _CounterWithRateBarState();
}
class _CounterWithRateBarState extends State<CounterWithRateBar> {
// const CounterWithRateBar({
// Key? key,
// }) : super(key: key);
late double _rating;
int _ratingBarMode = 1;
double _initialRating = 2.0;
IconData? _selectedIcon;
#override
void initState() {
super.initState();
_rating = _initialRating;
}
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CartCounter(),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children:
<Widget>[
SizedBox(
height: 10.0,
),
_ratingBar(_ratingBarMode),
SizedBox(height: 5.0),
Text(
'Rating: $_rating',
style: TextStyle(fontWeight: FontWeight.bold),
),
]
),
],
);
}
Widget _ratingBar(int mode) {
return RatingBar.builder(
initialRating: _initialRating,
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: true,
unratedColor: Colors.amber.withAlpha(50),
itemCount: 5,
itemSize: 25.0,
itemPadding: EdgeInsets.symmetric(horizontal: 2.0),
itemBuilder: (context, _) => Icon(
_selectedIcon ?? Icons.star,
color: Colors.amber,
),
onRatingUpdate: (rating) {
setState(() {
_rating = rating;
});
},
updateOnDrag: true,
);
}
}

You have small mistake in buildOutlineButtonDefinition
You immediately calling press function and not using is as callback;
From
onPressed: press(),
To
onPressed: () => press(),
Full definition would be
SizedBox buildOutlineButton(
{required IconData icon, required Function press}) {
return SizedBox(
width: 40,
height: 32,
child: OutlinedButton(
style: OutlinedButton.styleFrom(
padding: EdgeInsets.zero,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(13.0)),
),
onPressed: () => press(),
child: Icon(icon),
),
);
}

Related

Unsupported operation: Nan or infinity toInt for Tween Animation

I have found a code that i tried to replicate. It has an app itself and it is working. However when i tried to write the code down it shows the problem Unsupported operation NaN or infinity toInt for a function named TweenAnimation. I am still trying to learn how to use tween animation so any pros have any idea on this problem?
below is the code for the animation
import 'package:flutter/material.dart';
class AnimatedFlipCounter extends StatelessWidget {
final int value;
final Duration duration;
final double size;
final Color color;
const AnimatedFlipCounter({
Key? key,
required this.value,
required this.duration,
this.size = 72,
this.color = Colors.black,
}) : super(key: key);
#override
Widget build(BuildContext context) {
List<int> digits = value == 0 ? [0] : [];
int v = value;
if (v < 0) {
v *= -1;
}
while (v > 0) {
digits.add(v);
v = v ~/ 10;
}
return Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(digits.length, (int i) {
return _SingleDigitFlipCounter(
key: ValueKey(digits.length - i),
value: digits[digits.length - i - 1].toDouble(),
duration: duration,
height: size,
width: size / 1.8,
color: color,
);
}),
);
}
}
class _SingleDigitFlipCounter extends StatelessWidget {
final double value;
final Duration duration;
final double height;
final double width;
final Color color;
const _SingleDigitFlipCounter({
required Key key,
required this.value,
required this.duration,
required this.height,
required this.width,
required this.color,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return TweenAnimationBuilder(
tween: Tween(begin: value, end: value),
duration: duration,
builder: (context,double value, child) {
final whole = 1.0 ~/ value ;
final decimal = value - whole;
return SizedBox(
height: height,
width: width,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
_buildSingleDigit(
digit: whole % 10,
offset: height * decimal,
opacity: 1.0 - decimal,
),
_buildSingleDigit(
digit: (whole + 1) % 10,
offset: height * decimal - height,
opacity: decimal,
),
],
),
);
},
);
}
Widget _buildSingleDigit({required int digit, required double offset, required double opacity}) {
return Positioned(
child: SizedBox(
width: width,
child: Opacity(
opacity: opacity,
child: Text(
"$digit",
style: TextStyle(
fontSize: height, color: color, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
),
bottom: offset,
);
}
below is the main page that calls this widget
import 'package:carousel_slider/carousel_slider.dart';
import 'package:daily5/helpers/constants_tasbih.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
import 'package:vibration/vibration.dart';
import '../../helpers/animated_flip_counter.dart';
class Tasbih extends StatefulWidget {
const Tasbih({Key? key}) : super(key: key);
#override
_TasbihState createState() => _TasbihState();
}
class _TasbihState extends State<Tasbih> {
final PageController _controller =
PageController(viewportFraction: 0.1, initialPage: 5);
final int _numberOfCountsToCompleteRound = 33;
int _imageIndex = 1;
int _beadCounter = 0;
int _roundCounter = 0;
int _accumulatedCounter = 0;
bool _canVibrate = true;
bool _isDisposed = false;
final List<Color> _bgColour = [
Colors.teal.shade50,
Colors.lime.shade50,
Colors.lightBlue.shade50,
Colors.pink.shade50,
Colors.black12
];
final CarouselController _buttonCarouselController = CarouselController();
#override
void initState() {
super.initState();
_loadSettings();
}
#override
void dispose() {
_isDisposed = true;
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: _clicked,
onVerticalDragStart: (_) => _clicked(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
flex: 2,
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: [
const SizedBox(width: 45),
IconButton(
tooltip: 'Change colour',
icon: const Icon(Icons.palette),
onPressed: () {
setState(() {
_imageIndex < 5
? _imageIndex++
: _imageIndex = 1;
});
}),
IconButton(
tooltip: 'Reset counter',
icon: const Icon(Icons.refresh),
onPressed: () {
confirmReset(context, _resetEverything);
}),
],
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
textDirection: TextDirection.ltr,
children: <Widget>[
_Counter(
counter: _roundCounter, counterName: 'Round'),
_Counter(counter: _beadCounter, counterName: 'Beads'),
],
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 32),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text('Accumulated'),
const SizedBox(width: 10),
AnimatedFlipCounter(
value: _accumulatedCounter,
duration: const Duration(milliseconds: 730),
size: 14),
],
),
),
CarouselSlider(
carouselController: _buttonCarouselController,
options: CarouselOptions(
height: 100.0,
enlargeCenterPage: true,
),
items: [1, 2, 3, 4].map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.symmetric(
horizontal: 5.0),
decoration: BoxDecoration(
color: _bgColour[_imageIndex - 1],
borderRadius: BorderRadius.circular(12)),
child: Image.asset('assets/images/zikr/$i.png'));
},
);
}).toList(),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: () {
_buttonCarouselController.previousPage();
},
icon: const Icon(Icons.navigate_before)),
IconButton(
onPressed: () {
_buttonCarouselController.nextPage();
},
icon: const Icon(Icons.navigate_next)),
],
),
const Spacer()
],
),
)),
Expanded(
flex: 1,
child: PageView.builder(
reverse: true,
physics: const NeverScrollableScrollPhysics(),
controller: _controller,
scrollDirection: Axis.vertical,
itemBuilder: (_, __) {
return Image.asset(
'assets/images/beads/bead-$_imageIndex.png',
);
},
itemCount: null,
),
),
],
),
),
);
}
void _loadSettings() async {
bool? canVibrate = await Vibration.hasVibrator();
if (!_isDisposed) {
setState(() {
_canVibrate = canVibrate!;
_loadData();
});
}
}
void _loadData() {
if (!_isDisposed) {
setState(() {
_beadCounter = GetStorage().read(kBeadsCount) ?? 0;
_roundCounter = GetStorage().read(kRoundCount) ?? 0;
_accumulatedCounter =
_roundCounter * _numberOfCountsToCompleteRound + _beadCounter;
});
}
}
void _resetEverything() {
GetStorage().write(kBeadsCount, 0);
GetStorage().write(kRoundCount, 0);
_loadData();
}
void _clicked() {
if (!_isDisposed) {
setState(() {
_beadCounter++;
_accumulatedCounter++;
if (_beadCounter > _numberOfCountsToCompleteRound) {
_beadCounter = 1;
_roundCounter++;
if (_canVibrate) Vibration.vibrate(duration: 100, amplitude: 100);
}
});
}
GetStorage().write(kBeadsCount, _beadCounter);
GetStorage().write(kRoundCount, _roundCounter);
int nextPage = _controller.page!.round() + 1;
_controller.animateToPage(nextPage,
duration: const Duration(milliseconds: 200), curve: Curves.easeIn);
}
}
class _Counter extends StatelessWidget {
const _Counter(
{Key? key,
required this.counter,
this.tsCounter =
const TextStyle(fontSize: 50, fontWeight: FontWeight.bold),
required this.counterName,
this.tsCounterName = const TextStyle(
fontSize: 20,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w300)})
: super(key: key);
final int counter;
final TextStyle tsCounter;
final String counterName;
final TextStyle tsCounterName;
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
AnimatedFlipCounter(
duration: const Duration(milliseconds: 300),
value: counter,
),
Text(counterName, style: tsCounterName)
],
);
}
}
void confirmReset(BuildContext context, VoidCallback callback) {
const _confirmText = Text('Confirm', style: TextStyle(color: Colors.red));
const _cancelText = Text('Cancel');
const _dialogTitle = Text("Reset Counter?");
const _dialogContent = Text("This action can't be undone");
void _confirmResetAction() {
callback();
showSnackBar(
context: context,
label: 'Cleared',
icon: CupertinoIcons.check_mark_circled);
Navigator.of(context).pop();
}
showDialog(
context: context,
builder: (_) {
return kIsWeb
? AlertDialog(
title: _dialogTitle,
content: _dialogContent,
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: _cancelText,
),
TextButton(
onPressed: _confirmResetAction,
child: _confirmText,
),
],
)
: CupertinoAlertDialog(
title: _dialogTitle,
content: _dialogContent,
actions: [
CupertinoDialogAction(
child: _cancelText,
onPressed: () => Navigator.of(context).pop(),
),
CupertinoDialogAction(
child: _confirmText,
onPressed: _confirmResetAction,
),
],
);
},
);
}
void showSnackBar({required BuildContext context, required String label, required IconData icon}) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
behavior: SnackBarBehavior.floating,
content: Row(
children: [
Icon(
icon,
color: Colors.white60,
),
const SizedBox(width: 5),
Text(label)
],
),
),
);
}
Supposedly it should beads that can be counted down but the animation cant load.

How to remove item from cart in flutter/ dart

How to remove cart items from a list in flutter when you have a seperate list widget ?
I have three files that contain the following code.
carts.dart => where I display all the list items
cart_list_item => where I have created a widget.
api_services.dart => from where I am accessing the functions.
It was working when the cart list widget and cart list was in a single file.
but to increment cart quantity I had to separate them.
CARTS.DART
class _CartsListState extends State<CartsList> {
List cartList = [];
getProducts() async {
var resp = await http.get(
Uri.parse("https://abc"));
cartList.addAll(jsonDecode(resp.body));
setState(()=>{});
return jsonDecode(resp.body);
}
#override
void initState() {
super.initState();
getProducts();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(10),
child: FutureBuilder(
future: getProducts(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: cartList.length,
itemBuilder: (BuildContext context, int index) {
var path = "https://abc";
var img = cartList[index]['image'] ?? 'default.png';
return MyCartListItem(
cartName: cartList[index]['english_name'],
cartQuantity: 2,
cartImage: path + img,
cartPrice: cartList[index]['mrp'].toString(),
cartIndex: 5);
},
);
} else {
return const LinearProgressIndicator();
}
},
),
),
);
}
}
cart_list_item.dart
class MyCartListItem extends StatefulWidget {
const MyCartListItem(
{Key? key,
required this.cartName,
required this.cartQuantity,
required this.cartImage,
required this.cartPrice,
required this.cartIndex})
: super(key: key);
final String cartName;
final int cartQuantity;
final String cartImage;
final String cartPrice;
final int cartIndex;
#override
State<MyCartListItem> createState() => _MyCartListItemState();
}
#override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(10.5),
child: Row(children: [
const SizedBox(
width: 10,
),
SizedBox(
width: 70,
height: 70,
child: Image.network(widget.cartImage),
),
const SizedBox(
width: 50,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
// ignore: prefer_const_literals_to_create_immutables
children: [
Container(
child: Text(
widget.cartName,
style: const TextStyle(
overflow: TextOverflow.clip,
),
),
),
const SizedBox(
width: 10,
),
],
),
const SizedBox(
height: 7,
),
Text(
"Rs. ${widget.cartPrice}",
style: const TextStyle(
fontWeight: FontWeight.bold, color: Colors.grey),
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
InkWell(
onTap: () {
// setState() {
// _itemCount--;
// print(_itemCount);
// }
},
child: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Colors.deepOrange[50],
),
child: const Icon(
CupertinoIcons.minus,
)),
),
const SizedBox(
width: 10,
),
Text(_itemCount.toString()),
const SizedBox(
width: 10,
),
InkWell(
// onTap: () {
// setState() => {_itemCount++};
// },
child: Container(
height: 30,
width: 30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Colors.deepOrange[50],
),
child: const Icon(
CupertinoIcons.plus,
)),
),
const SizedBox(
width: 15,
),
InkWell(
onTap: () {
ApiServices.removeCartItem(0);
// setState(() {});
final snackBarData = SnackBar(
behavior: SnackBarBehavior.floating,
content: Row(
children: const [
Icon(Icons.shopping_bag),
SizedBox(
width: 10,
),
Text('Product removed from cart !!!'),
],
),
);
ScaffoldMessenger.of(context).showSnackBar(snackBarData);
},
child: const Icon(
CupertinoIcons.trash,
color: Colors.red,
),
)
],
)
],
)
]),
),
);
}
}
api services.dart*
static removeCartItem(int indexNumber) async {
cartList.removeAt(indexNumber);
}
You need to update your view because data in list was changed. If you are using setState for in, implement callback in CartListItem that allows you to handle item deletion and update view in this callback. It should be looks like:
class MyCartListItem extends StatefulWidget {
const MyCartListItem(
{Key? key,
required this.cartName,
required this.cartQuantity,
required this.cartImage,
required this.cartPrice,
required this.cartIndex,
required this.onItemRemoved,
}) : super(key: key);
final String cartName;
final int cartQuantity;
final String cartImage;
final String cartPrice;
final int cartIndex;
final Function onItemRemoved;
#override
State<MyCartListItem> createState() => _MyCartListItemState();
}
And in CartListItem:
onTap: () => widget.onItemRemoved(index);
its already answered, but if you still had i problem, i try to make it clear, you can ask later if not working.
in you listViewBuilder :
return ListView.builder(
itemCount: cartList.length,
itemBuilder: (BuildContext context, int index) {
var path = "https://abc";
var img = cartList[index]['image'] ?? 'default.png';
return MyCartListItem(
cartName: cartList[index]['english_name'],
cartQuantity: 2,
cartImage: path + img,
cartPrice: cartList[index]['mrp'].toString(),
cartIndex: 5,
//------- this line -------------
removeFunction:(){
ApiServices.removeCartItem(index);
}
);
},
);
in your Cardlistitem :
class MyCartListItem extends StatefulWidget {
const MyCartListItem(
{Key? key,
required this.cartName,
required this.cartQuantity,
required this.cartImage,
required this.cartPrice,
required this.cartIndex,
required this.removeFuntion,
}) : super(key: key);
final String cartName;
final int cartQuantity;
final String cartImage;
final String cartPrice;
final int cartIndex;
final Function removeFunction;
#override
State<MyCartListItem> createState() => _MyCartListItemState();
}
.... Rest OF code
// and here :
InkWell(
onTap: () {
//------- THIS LINE -----:
widget.removeFunction;
//-----------------------
// setState(() {});
final snackBarData = SnackBar(
behavior: SnackBarBehavior.floating,
content: Row(
children: const [
Icon(Icons.shopping_bag),
SizedBox(
width: 10,
),
Text('Product removed from cart !!!'),
],
),
);
ScaffoldMessenger.of(context).showSnackBar(snackBarData);
},
child: const Icon(
CupertinoIcons.trash,
color: Colors.red,
),
)

Checkbox doesn't change when clicked in dropdownbutton

I am using DropdownButton and I am facing the following issue. I'm using a checkbox in elements, but when I click on an element, I don't get a checkmark indicating that the checkbox has been clicked. As a result, I need to close and reopen it, and then I will see the changes that were clicked on the "checkbox". The second problem is that when I select one element, all elements are selected for me. As a final result, I need to get so that I can select an element and the checkbox is immediately marked, if 2 elements are needed, then two, and so on. Tell me how to fix these problems, I will be grateful for the help?
dropdown
class DropdownWidget extends StatefulWidget {
List<String> items;
SvgPicture? icon;
double width;
DropdownWidget({
Key? key,
required this.items,
required this.icon,
required this.width,
}) : super(key: key);
#override
State<DropdownWidget> createState() => _DropdownWidgetState();
}
class _DropdownWidgetState extends State<DropdownWidget> {
String? selectedValue;
bool isChecked = false;
#override
void initState() {
super.initState();
if (widget.items.isNotEmpty) {
selectedValue = widget.items[1];
}
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton2(
items: widget.items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: constants.Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: Center(
child: Row(
children: [
if (item == selectedValue)
const SizedBox(
width: 0,
),
Expanded(
child: Text(
item,
style: constants.Styles.smallTextStyleWhite,
),
),
Checkbox(
checkColor: Colors.black,
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value!;
});
},
),
],
),
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 191,
dropdownWidth: 140,
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: constants.Colors.purpleMain,
),
color: constants.Colors.greyDark,
),
selectedItemBuilder: (context) {
return widget.items.map(
(item) {
return Row(
children: [
widget.icon ?? const SizedBox(),
const SizedBox(width: 8),
Text(
item,
style: constants.Styles.bigBookTextStyleWhite,
),
],
);
},
).toList();
},
),
),
);
}
}
items
final List<String> items = const [
"All EV's",
'Main EV',
'<EV2>',
];
I hope this example explains the concept. For simplcity I made simple a new file, run it and see the results:
Then main idea in two lists, _checkList contain values of the CheckBox and _selectedList handles the main dropdown widget to show the selection.
Feel free to ask any questions and I'm happy to help
import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
const TestPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const AnimationDemo(number: 5);
}
}
class AnimationDemo extends StatefulWidget {
const AnimationDemo({Key? key, this.number = 2}) : super(key: key);
final int number;
#override
State<AnimationDemo> createState() => _AnimationDemoState();
}
class _AnimationDemoState extends State<AnimationDemo> {
late List<bool> _checkList;
late List<int> _selectedIndex;
bool _isOpen = false;
#override
void initState() {
_checkList = List.filled(widget.number, false);
_selectedIndex = <int>[];
super.initState();
}
List<DropDownItem> generateItems() {
var tmp = <DropDownItem>[];
for (var i = 0; i < _checkList.length; i++) {
tmp.add(DropDownItem(
isChecked: _checkList[i],
onChanged: (value) {
setState(() {
_checkList[i] = value!;
if (value && !_selectedIndex.contains(i)) {
_selectedIndex.add(i);
} else {
_selectedIndex.remove(i);
}
});
},
));
}
return tmp;
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
child: Text((_selectedIndex.isEmpty)
? 'Nothing Selected'
: _selectedIndex.join(',')),
),
GestureDetector(
onTap: () {
setState(() {
_isOpen = !_isOpen;
});
},
child: const Icon(Icons.arrow_downward),
),
],
),
AnimatedOpacity(
opacity: (_isOpen) ? 1 : 0,
duration: const Duration(milliseconds: 300),
child: Column(
mainAxisSize: MainAxisSize.min,
children: generateItems(),
),
)
],
),
);
}
}
class DropDownItem extends StatelessWidget {
final bool isChecked;
final Function(bool?)? onChanged;
const DropDownItem({Key? key, this.onChanged, this.isChecked = false})
: super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: [
const Expanded(child: Text('Demo item')),
Checkbox(value: isChecked, onChanged: onChanged)
],
);
}
}
Here's how to achieve the Multiselect dropdown with DropdownButton2:
final List<String> items = [
'Item1',
'Item2',
'Item3',
'Item4',
];
List<String> selectedItems = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Align(
alignment: AlignmentDirectional.center,
child: Text(
'Select Items',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
),
items: items.map((item) {
return DropdownMenuItem<String>(
value: item,
//disable default onTap to avoid closing menu when selecting an item
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
final _isSelected = selectedItems.contains(item);
return InkWell(
onTap: () {
_isSelected
? selectedItems.remove(item)
: selectedItems.add(item);
//This rebuilds the StatefulWidget to update the button's text
setState(() {});
//This rebuilds the dropdownMenu Widget to update the check mark
menuSetState(() {});
},
child: Container(
height: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
_isSelected
? const Icon(Icons.check_box_outlined)
: const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
],
),
),
);
},
),
);
}).toList(),
//Use last selected item as the current value so if we've limited menu height, it scroll to last item.
value: selectedItems.isEmpty ? null : selectedItems.last,
onChanged: (value) {},
buttonHeight: 40,
buttonWidth: 140,
itemHeight: 40,
itemPadding: EdgeInsets.zero,
selectedItemBuilder: (context) {
return items.map(
(item) {
return Container(
alignment: AlignmentDirectional.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
selectedItems.join(', '),
style: const TextStyle(
fontSize: 14,
overflow: TextOverflow.ellipsis,
),
maxLines: 1,
),
);
},
).toList();
},
),
),
),
);
}
Also, I've added it as an example to the package doc "Example 4" so you can get back to it later.

Get all the scores from all widgets

I am building a quiz app and I created a custom widget to save me a lot of time as I have a lot of questions for the quiz. Everything works apart from the scoring system. If I create multiple instances of the same widget the score will not be incremented and it will stay on 1. Is there any way I can pass each score of the widgets to a global variable in my main widget so then I can add all the scores? (I'm new to flutter).
Custom Widget
class Questions extends StatefulWidget {
final String imagePath;
final String question;
final String answer1;
final String answer2;
final String answer3;
final String answer4;
final bool iscorrectAnswer1;
final bool iscorrectAnswer2;
final bool iscorrectAnswer3;
final bool iscorrectAnswer4;
int score = 0;
bool questionsAnswered = false;
Questions(
this.imagePath,
this.question,
this.answer1,
this.answer2,
this.answer3,
this.answer4,
this.iscorrectAnswer1,
this.iscorrectAnswer2,
this.iscorrectAnswer3,
this.iscorrectAnswer4,
);
#override
_QuestionsState createState() => _QuestionsState();
}
class _QuestionsState extends State<Questions> {
disableButton() {
setState(() {
widget.questionsAnswered = true;
Quiz().score += widget.score;
});
}
#override
#override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
width: 600,
height: 600,
child: Image.asset(widget.imagePath),
),
Align(
alignment: Alignment.topCenter,
child: Padding(
padding: EdgeInsets.only(
top: 20,
),
child: Text(
widget.question,
style: TextStyle(
color: Colors.white,
fontSize: 38,
),
),
)),
Padding(
padding: EdgeInsets.only(
top: 40,
),
child: SizedBox(
width: 500,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Color(0xFF304e60),
),
),
child: Text(
widget.answer1,
style: TextStyle(
color: Colors.white,
fontSize: 15,
),
),
onPressed: widget.questionsAnswered == false
? () {
setState(() {
if (widget.iscorrectAnswer1 == true) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Correct!'),
),
);
disableButton();
widget.score += 1;
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text('Wrong Answer!'),
));
}
});
print(widget.iscorrectAnswer1);
print(widget.score);
}
: null),
),
)),
Padding(
padding: EdgeInsets.only(
top: 10,
),
child: SizedBox(
width: 500,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Color(0xFF565462))),
child: Text(
widget.answer2,
style: TextStyle(
color: Colors.white,
fontSize: 15,
),
),
onPressed: widget.questionsAnswered == false
? () {
setState(() {
if (widget.iscorrectAnswer2 == true) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Correct!'),
),
);
widget.score += 1;
} else {
disableButton();
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text('Wrong Answer!'),
));
}
});
}
: null),
),
)),
Padding(
padding: EdgeInsets.only(
top: 10,
),
child: SizedBox(
width: 500,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Color(0xFF84693b))),
child: Text(
widget.answer3,
style: TextStyle(
color: Colors.white,
fontSize: 15,
),
),
onPressed: widget.questionsAnswered == false
? () {
setState(() {
if (widget.iscorrectAnswer3 == true) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Correct!'),
),
);
widget.score += 1;
} else {
disableButton();
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text('Wrong Answer!'),
));
}
});
}
: null),
),
),
)
],
);
}
}
Main widget where I call this custom widget
class Quiz extends StatefulWidget {
Quiz({Key? key}) : super(key: key);
int score = 0;
#override
_QuizState createState() => _QuizState();
}
class _QuizState extends State<Quiz> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('CyberQuiz'),
),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Questions(
'images/malware_quiz.jpeg',
'1. What is a malware?',
'Designed to damage computers, servers or any other devices',
"Used to get user's credentials",
"It's used to destroy networks",
'',
true,
false,
false,
false,
),
],
)));
}
}
As you suggest in your question, you could create a global variable and increment/decrease/reset that.
Basic example code:
import 'package:flutter/material.dart';
class Score {
static int score = 0;
}
class ScoreCounter extends StatefulWidget {
const ScoreCounter({Key? key}) : super(key: key);
#override
State<ScoreCounter> createState() => _ScoreCounterState();
}
class _ScoreCounterState extends State<ScoreCounter> {
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: ElevatedButton(
onPressed: () {
setState(() {
Score.score++;
});
},
child: Text('increase score'),
),
),
Expanded(child: Text(Score.score.toString()))
],
);
}
}
Another option is to use the Provider package - link here which has an example
Provider Package

How can I update the style of an element inside a list dynamically in Flutter?

I am making a Fast Reading exercise app with flutter. I tried run foreach loop on my list to update TextSpans opacity but it didn't work. After that, I tried to replace the element with a new TextSpan and a new opacity, element changed inside the list but it didn't render on screen. Here is my code.
var textList = <TextSpan>[];
#override
void initState() {
super.initState();
text.split(' ').forEach((element) {
textList.add(TextSpan(text:element));
});
}
Widget _textArea() {
return FractionallySizedBox(
widthFactor: 0.9,
heightFactor: 0.9,
child: DecoratedBox(
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
width: 1,
),
),
child: RichText(
text: TextSpan(
children: textList
),
)
));
}
I need to update the opacities of each element inside textList every second and the update function has to start with ``ònPress```event.
I am stuck on that issue.
FULL CODE
import 'package:flutter/material.dart';
class HomePeageReaderWidget extends StatefulWidget {
const HomePeageReaderWidget({Key? key}) : super(key: key);
#override
_HomePageReaderWidgetState createState() => _HomePageReaderWidgetState();
}
class _HomePageReaderWidgetState extends State<HomePeageReaderWidget> {
var text =
"""Gaziantep şehri Türkiye'nin güneydoğusundadır. Çok güzel bir şehirdir. Belki İstanbul ve Ankara kadar büyük değildir, ama yine de burada bir milyonun üstünde insan yaşıyor. Gaziantep'te iş alanları çok geniştir, herkes çalışıyor. Birçok fabrikalar ve atölyeler vardır. Ayrıca bir de Gaziantep Üniversitesi vardır. Üniversite şehirden biraz uzak, ama yurt da üniversitenin yanında. Bunun için ulaşım sorunu yok.Gaziantep'te yazın hava çok sıcak oluyor, insanlar evlerinden ve iş yerlerinden dışarıya çıkmıyorlar. Gece balkonlarda yatıyorlar. Kışın ise havalar sert, sokaklar ise her zaman ıslaktır.""";
var textList = <TextSpan>[];
#override
void initState() {
super.initState();
text.split(' ').forEach((element) {
textList.add(TextSpan(text: element));
});
}
#override
Widget build(BuildContext context) {
Widget _controlRow() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.skip_previous),
iconSize: 50,
color: const Color(0xFFffcd05),
)
],
),
Column(
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.pause_circle),
iconSize: 50,
color: const Color(0xFF91268e),
)
],
),
Column(
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.skip_next),
iconSize: 50,
color: const Color(0xFFffcd05),
)
],
),
],
);
}
Widget _textArea() {
return FractionallySizedBox(
widthFactor: 0.9,
heightFactor: 0.9,
child: DecoratedBox(
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
width: 1,
),
),
child: RichText(
text: TextSpan(children: textList),
)));
}
return Column(
children: [
Expanded(
flex: 6,
child: _textArea(),
),
Expanded(
child: _controlRow(),
),
Container(
width: 300,
child: ElevatedButton.icon(
onPressed: () {
// Respond to button press
},
icon: Icon(Icons.play_arrow, size: 18),
label: Text("Hızlı Egzersiz"),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(const Color(0xFF075098)),
),
),
)
],
);
}
}
You need to use setState( ) so your changes are reflected in the client.
Dont forget that you need to keep a StatefulWidget so that setState works
Code:
onPressed: () {
setState(() {
yourOpacityValue = updatedOpacityValue; });
},