首页 > 解决方案 > 在单独的小部件颤动上更新状态

问题描述

我试图弄清楚当我按下按钮时如何更新小部件的状态。

这里有几个截图来说明我想要完成的事情:

在此处输入图像描述

在此处输入图像描述

当我热重新加载应用程序时,更新生效,但当我按下对话框上的更新按钮时状态不会更新。

我知道有一些技术可以让它工作,但我无法通过构造函数传递一个函数来更新它。

我也不太清楚如何在不传递一些值的情况下使用 provider.of(context) 。两个地方(mainDebt 小部件和 allDebts 小部件)都没有使用任何值。

主页代码非常简单。一个无状态的小部件,其中包含我需要显示的不同小部件:

class Home extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: SingleChildScrollView(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              SizedBox(
                height: 30,
              ),
              HpHeader(),
              SizedBox(height: 30),
              QuoteBox(),
              SizedBox(height: 30),  
       
              MainDebtDebt(),
              SizedBox(height: 30),
              AdCard(),

              AllDebtsCard(),
              SizedBox(height: 10),
              RaisedButton(
                  child: Text('Enter Debt'),
                  onPressed: () => Navigator.pushNamed(context, '/enterDebt1')),
              SizedBox(height: 10),
              AdCard(),
              //etc........

mainDebtDebt 是我需要更新状态的小部件。它正在从当我按下对话框上的更新按钮时设置的 SharedPreferences 读取数据:

import 'dart:async';

//import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:debt_zero_2/classes/icon_class.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class MainDebtDebt extends StatefulWidget {

  
  @override
  _MainDebtDebtState createState() => _MainDebtDebtState();
}

class _MainDebtDebtState extends State<MainDebtDebt> {
   
   bool thenum = true;

  static DebtModel debtIcons = DebtModel();
  bool getGoalType = true;
  double balance = 0.0;
  String name = '';
  String type = ''; 
  int numOfDebts = 0;
  double safetyBalance = 0.0;

  double mainSnowballOpeningBalance = 0.0;

 

  Future<void> getGoalTypeFlag() async {
    final SharedPreferences preferences = await SharedPreferences.getInstance();
    final sortBy = preferences.getInt('sortBySnowOrAva');
    setState(() {
       if (sortBy == 1){
      balance = preferences.getDouble('mainDebtFieldSnowball');
      type = preferences.getString('mainDebtFieldSnowballType');
      name = preferences.getString('mainDebtFieldSnowballName');}

       if (sortBy == 2){
      balance = preferences.getDouble('mainAvalancheBalance');
      type = preferences.getString('mainAvalancheBalanceType');
      name = preferences.getString('mainAvalancheBalanceName');
       }

      mainSnowballOpeningBalance = preferences.getDouble('openingBalance');  

      safetyBalance = preferences.getDouble('safetyBalance');
      getGoalType = preferences.getBool('mainGoalIsDebts');
      numOfDebts = preferences.getInt('numberOfDebts');     
    
    });
  }



  @override
  void initState() {
    super.initState();
    getGoalTypeFlag();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      decoration: BoxDecoration(border: Border.all()),
      child: Column(
        children: <Widget>[
          Text(getGoalType
              ? 'I\'m Knocking Out This Payment:'
              : 'I\'m Building My Safety Fund'),
          SizedBox(
            height: 15,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                getGoalType
                    ? debtIcons.getDebtIcon(type)
                    : '',
                style: TextStyle(fontSize: 30),
              ),
              SizedBox(
                width: 20,
              ),
              Text(getGoalType ? name : 'Safety Fund'),
            ],
          ),
          SizedBox(
            height: 15,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(getGoalType ? 'Remaining Balance:' : 'Saved:'),
              SizedBox(
                width: 15,
              ),
              Text(getGoalType
                  ? '\$' + balance.toStringAsFixed(0)
                  : safetyBalance.toStringAsFixed(0))
            ],
          ),
          SizedBox(
            height: 15,
          ),
          Column(
            children: <Widget>[
              Text('Current Progress:'),
              SizedBox(
                height: 10,
              ),
              Container(
                decoration: BoxDecoration(border: Border.all()),
                height: 22,
                width: 202,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Flexible(
                      child: FractionallySizedBox(
                        widthFactor: .75,
                        //fix this
                        // 1 - mainSnowballBalance / mainSnowballOpeningBalance,
                        child: Container(
                          color: Colors.green,
                        ),
                      ),
                    )
                  ],
                ),
              ),
              SizedBox(
                height: 15,
              ),
              RaisedButton(
                child: Text(getGoalType ? 'MAKE A PAYMENT' : 'MAKE A DEPOSIT'),
                onPressed: () {
                  Navigator.of(context).pushNamed('/makePayment');
                },
              ),
              SizedBox(
                height: 30,
              ),
              RaisedButton(
                child: Text('GET DATA'),
                onPressed: ()async {
                 
                  SharedPreferences pref = await SharedPreferences.getInstance();
                      

                    String thenum = pref.getString('debtId');
                    //pref.setBool('isInOb', null);
                    print(thenum);
                  
                },
              ),
            ],
          )
        ],
      ),
    );
  }
}

排序对话框当前位于 AllDebtsCard 中。它目前可以分别按最高利息或最低余额对列表进行排序:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:debt_zero_2/classes/min_debt_class.dart';
//import 'package:debt_zero_2/classes/icon_class.dart';
import 'package:debt_zero_2/widgets/provider_widget.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AllDebtsCard extends StatefulWidget {
  @override
  _AllDebtsCardState createState() => _AllDebtsCardState();
}

class _AllDebtsCardState extends State<AllDebtsCard> {
  int debtValue = 1;

  int group;

  void setValues() async {
    SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
    final uid = await Provider.of(context).auth.getUidPref();
    final db = Firestore.instance;
    setState(() {
      sharedPrefs.setInt('sortBySnowOrAva', debtValue);
      SetMainDebt().setMainDebt();
    });

    db
        .collection('userPreferences')
        .document(uid)
        .updateData({'sortBySnowOrAva': debtValue});
  }

  getValues() async {
    SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
    int intValue = sharedPrefs.getInt('sortBySnowOrAva');

    return intValue;
  }

  restore() async {
    final SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
    setState(() {
      group = (sharedPrefs.getInt('sortBySnowOrAva') ?? false);
    });
  }

  final dbPath = Firestore.instance.collection('userDebts');

  Stream<QuerySnapshot> dbStream(BuildContext context) async* {
    final uid = await Provider.of(context).auth.getUidPref();
    final intValues = await getValues();
    yield* intValues == 1
        ? dbPath
            .document(uid)
            .collection('debts')
            .orderBy('balance')
            .snapshots()
        : dbPath
            .document(uid)
            .collection('debts')
            .orderBy('interest', descending: true)
            .snapshots();
  }

  @override
  void initState() {
    super.initState();
    restore();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        RaisedButton(
          child: Text('SORT'),
          onPressed: () {
            showDialog(
                barrierDismissible: false,
                context: context,
                builder: (BuildContext context) {
                  return StatefulBuilder(
                    builder: (context, setState) {
                      return AlertDialog(
                        title: Text('Sort Debts By:'),
                        content: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: <Widget>[
                            RadioListTile(
                              value: 1,
                              secondary: IconButton(
                                onPressed: () {
                                  showDialog(
                                      context: context,
                                      builder: (BuildContext context) {
                                        return AlertDialog(
                                          title: Text('Debt Snowball:'),
                                          content: Text(
                                              'This is an explanation of debt snowball'),
                                          actions: <Widget>[
                                            FlatButton(
                                              child: Text('OK'),
                                              onPressed: () {
                                                Navigator.pop(context);
                                              },
                                            )
                                          ],
                                        );
                                      });
                                },
                                icon: Icon(Icons.help_outline),
                              ),
                              title: Text('Snowball'),
                              groupValue: group,
                              onChanged: (T) {
                                setState(() {
                                  group = T;
                                  debtValue = 1;
                                });
                              },
                            ),
                            RadioListTile(
                              value: 2,
                              title: Text('Avalanche'),
                              secondary: IconButton(
                                onPressed: () {},
                                icon: Icon(Icons.help_outline),
                              ),
                              groupValue: group,
                              onChanged: (T) {
                                setState(() {
                                  group = T;
                                  debtValue = 2;
                                });
                              },
                            )
                          ],
                        ),
                        actions: <Widget>[
                          FlatButton(
                            onPressed: () async {
                              setState(() {
                                setValues();
                              });
                              Navigator.pop(context);
                            },
                            child: Text('UPDATE'),
                          ),
                          FlatButton(
                            child: Text(
                              'CANCEL',
                              style: TextStyle(color: Colors.red),
                            ),
                            onPressed: () {
                              Navigator.pop(context);
                            },
                          ),
                        ],
                      );
                    },
                  );
                }).then((value) => setState(() {}));
          },
        ),
        StreamBuilder<QuerySnapshot>(
            stream: dbStream(context),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                final debts = snapshot.data.documents;
                List<Widget> debtWidgets = [];
                for (var debt in debts) {
                  final debtName = debt.data['name'];
                  final debtType = debt.data['type'];
                  final debtBalance = debt.data['balance'];
                  final debtDue = debt.data['due'].toDate();

                  final debtWidget = Card(
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text('$debtType'),
                        Text('$debtName'),
                        Text(DateFormat.MMMd().format(debtDue)),
                        Text('$debtBalance'),
                        FlatButton(
                          child: Text(
                            'DELETE',
                            style: TextStyle(color: Colors.red),
                          ),
                          onPressed: () {
                            //When I delete a debt I need to update the 'debtMinimum' field in prefs and firestore
                          },
                        )
                      ],
                    ),
                  );

                  debtWidgets.add(debtWidget);
                }
                return Column(children: debtWidgets);
              }
              return Container();
            }),
      ],
    );
  }
}

我不反对尝试任何有效的技术。提升状态、提供者或其他任何东西(这不需要对架构进行整个重建(我知道这不是什么好东西))。我已经尝试了好几天来解决这个问题。任何帮助将不胜感激。谢谢

标签: flutterstate-management

解决方案


您可以包装小部件以使用 StreamBuilder 进行更新,然后在按下 RaisedButton 时将事件发送到流接收器。下面是一个简单的例子:

/// Some where in State class
class _SomeWidgetState extends State<SomeWidget> {
  /// Stream controller which takes integer identifiers
  StreamController<int> streamController;

  /// Result stream which converts int to UpdatableObject via function
  Stream<UpdatableObject> get stream => streamController.stream.asyncMap(_getObjectById);

  /// Takes object identifier and returns corresponding object.
  Future<UpdatableObject> _getObjectById(int id) {
    ...
    return UpdatableObject();
  }

  @override
  void initState() {
    super.initState();
    // Take from parent `Provider` widget
    streamController = Provider.of<int>(context, listen: false);
    // or create it here (depends on requirements)
    //streamController = StreamController<int>.broadcast();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<UpdatableObject>(
      stream: stream,
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          return Text(snapshot.error.toString();
        }
        if (!snapshot.hasData) {
          return CircularProgressIndicator();
        }
        // `snapshot.data` contains instance of `UpdatableObject`
        return TheWidgetToBeUpdated(data: snapshot.data); 
      }
    );
  }
}

推荐阅读