有状态的窗口小部件,其子状态未更新

时间:2018-09-06 14:06:46

标签: android ios dart flutter

我正在开发一个应用程序的一部分,该应用程序本质上只是在跟踪类似于货币形式的物理令牌。我正在尝试构建一个可重用的小部件,该小部件将该令牌数量的状态作为参数,并根据用户交互来增加/减少。为了清楚起见,我只包括了Widget的递减部分。我的问题:传递到窗口小部件中的令牌的状态是否没有更新,因为它只是对该状态的引用?还是我想念其他东西。

    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(),
                  ],
                ),
              ),
            ), 

1 个答案:

答案 0 :(得分:2)

通用解决方案如下:

父窗口小部件

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,
        ),
      ),
    );
  }
}

每个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

typedef TokenQuantityUpdatedFn = void Function(int newValue);

“旧式”枚举可以设置自定义值。

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';
}