Reputation: 79
I'm working on a part of an app that will essentially just be keeping track of physical tokens that are like forms of currency. I'm trying to build a reusable Widget that will take in the state of that token quantity as a parameter, and increment/decrement that based on user interaction. For the sake of clarity, I've just included the decrement part of the Widget. My question: is the state of the token that is getting passed into the widget not updating because it's just a reference to that state? Or am I missing something else.
class RedeemTokensState extends State<RedeemTokens> {
int oneQuantity = 0;
int fiveQuantity = 0;
int tenQuantity = 0;
int total = 0;
Widget _counterWidget(int tokenQuantity) {
return Row(
children: <Widget>[
Expanded(
child: IconButton(
icon: Icon(Icons.remove),
onPressed: () {
setState(() {
tokenQuantity = tokenQuantity - 1;
print(tokenQuantity);
});
},
),
),
),
}
Widget _buildOneField() {
return ListTile(
title: Text('\$1 Token'),
trailing: Container(width: 200.0, child: _counterWidget(oneQuantity)),
);
}
Widget _buildFiveField() {
return ListTile(
title: Text('\$5 Token'),
trailing: Container(width: 200.0, child: _counterWidget(fiveQuantity)),
);
}
Widget _buildTenField() {
return ListTile(
title: Text('\$10 Token'),
trailing: Container(width: 200.0, child: _counterWidget(tenQuantity)),
);
}
}
// main scaffold with build method
... Card(
child: Container(
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
_buildOneField(),
Divider(),
_buildFiveField(),
Divider(),
_buildTenField(),
Divider(),
_buildFreshConnectField(),
],
),
),
),
Upvotes: 2
Views: 3077
Reputation: 658087
A generic solution could look like:
Parent widget
class RedeemTokens extends StatefulWidget {
@override
RedeemTokensState createState() => RedeemTokensState();
}
class RedeemTokensState extends State<RedeemTokens> {
final _quantities = new Map<TokenType, int>.fromIterable(TokenType.values,
key: (k) => k, value: (k) => 0);
Widget build(BuildContext context) {
final widgets = <Widget>[];
for (final type in _quantities.keys) {
widgets
..add(
new TokenQuantity(
tokenType: type,
quantity: _quantities[type],
onQuantityUpdated: (newValue) {
setState(() {
print('\$${type.value}: $newValue');
print(_quantities);
_quantities[type] = newValue;
});
}),
)
..add(Divider());
}
// widgets.add(_buildFreshConnectField());
return Card(
child: Container(
padding: EdgeInsets.all(10.0),
child: Column(
children: widgets,
),
),
);
}
}
Child widget added once per TokenType
class TokenQuantity extends StatelessWidget {
const TokenQuantity(
{@required this.tokenType,
@required this.quantity,
this.onQuantityUpdated})
: assert(quantity != null);
final TokenType tokenType;
final int quantity;
final TokenQuantityUpdatedFn onQuantityUpdated;
Widget _counterWidget() {
return Row(
children: <Widget>[
Text('$quantity'),
Expanded(
child: IconButton(
icon: Icon(Icons.remove),
onPressed: () {
if (onQuantityUpdated != null) {
onQuantityUpdated(quantity - 1);
}
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return ListTile(
title: Text('\$${tokenType.value} Token'),
trailing: Container(width: 200.0, child: _counterWidget()),
);
}
}
Typedef for the event callback
typedef TokenQuantityUpdatedFn = void Function(int newValue);
"Old-style" enum to be able to set custom values.
class TokenType {
static const one = const TokenType(1);
static const fife = const TokenType(5);
static const ten = const TokenType(10);
static const values = const <TokenType>[one, fife, ten];
final int value;
const TokenType(this.value);
@override
String toString() => 'TokenType $\$value';
}
Upvotes: 2