flutter - 跨多个屏幕使用的Flutter Stateful Widget得以重建

标签 flutter dart widget stateful

我创建了下面的多选芯片小部件,它使用提供程序并侦听列表中的更改

小部件创建一个“选择筹码列表”,允许选择多个选择筹码

class MultiSelectChip extends StatefulWidget {
  final Function(List<String>) onSelectionChanged;

  MultiSelectChip({this.onSelectionChanged});

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

class _MultiSelectChipState extends State<MultiSelectChip> {
  List<String> selected = List();
  List<Clinic> clinicList = List();

  @override
  void didChangeDependencies() {
    final list = Provider.of<ClinicProvider>(context).clinics;

    final clinic = Clinic(
        id: null,
        name: "All Clinics",
        city: null,
        suburb: null,
        postcode: null,
        prate: null,
        udarate: null,
        goal: null,
        uid: null);

    clinicList.add(clinic);
    selected.add(clinicList[0].name);
    list.forEach((clinic) => clinicList.add(clinic));
    super.didChangeDependencies();
  }

  _buildList() {
    List<Widget> choices = List();

    clinicList.forEach((item) {
      choices.add(Padding(
        padding: const EdgeInsets.only(left: 5.0, right: 5.0),
        child: ChoiceChip(
          key: Key("${item.name}"),
          shape: selected.contains(item.name)
              ? RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(0),
                  ),
                )
              : RoundedRectangleBorder(
                  side: BorderSide(
                      color: Color.fromRGBO(46, 54, 143, 1), width: 1.0),
                  borderRadius: BorderRadius.circular(0.0),
                ),
          label: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(item.name),
          ),
          onSelected: (value) {
            setState(() {
              selected.contains(item.name)
                  ? selected.remove(item.name)
                  : selected.add(item.name);
              widget.onSelectionChanged(selected);
            });
          },
          selected: selected.contains(item.name),
          selectedColor: Color.fromRGBO(46, 54, 143, 1),
          labelStyle:
              selected.contains(item.name) ? kChipActive : kChipInActive,
          backgroundColor: Colors.transparent,
        ),
      ));
    });

    return choices;
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(left: 8.0, top: 5.0, bottom: 5.0),
      child: SizedBox(
        height: 50,
        width: double.infinity,
        child: ListView(
          scrollDirection: Axis.horizontal,
          children: _buildList(),
        ),
      ),
    );
  }
}

当我从该日志屏幕单击并转到NewLog屏幕并弹出回到日志屏幕时
class LogScreen extends StatefulWidget {
  static const String id = 'logscreen';
  @override
  _LogScreenState createState() => _LogScreenState();
}

class _LogScreenState extends State<LogScreen> {
  MonthSelector selectedMonth;
  List<String> selectedItems = List();

  static DateTime now = DateTime.now();
  static DateTime end = DateTime(now.year, now.month + 1, 0);
  static DateTime start = DateTime(now.year, now.month, 1);

  MonthSelector currentMonth = MonthSelector(
      monthName: DateFormat("MMMM").format(now),
      monthStart: start,
      monthEnd: end);

  void refreshData(MonthSelector selector) async {
    await Provider.of<LogProvider>(context, listen: false)
        .getLogs(selector.monthStart, selector.monthEnd);
    await Provider.of<LogProvider>(context, listen: false)
        .loadTreatments(selector.monthStart, selector.monthEnd);
  }

  @override
  Widget build(BuildContext context) {
    final List<LogSummary> list = Provider.of<LogProvider>(context).summary;
    final List<FlSpot> chartData = Provider.of<LogProvider>(context).spots;

    return Container(
      color: Color.fromRGBO(246, 246, 246, 1),
      child: Column(
        children: <Widget>[
          Row(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Expanded(
                  flex: 1,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      SizedBox(
                        height: 15,
                      ),
                      RawMaterialButton(
                        onPressed: () {
                          Navigator.pushNamed(context, NewLogScreen.id);
                        },
                        constraints: BoxConstraints.tight(Size(60, 60)),
                        child: Icon(
                          Icons.add,
                          color: Color.fromRGBO(255, 255, 255, 1),
                          size: 30,
                        ),
                        shape: CircleBorder(),
                        fillColor: Color.fromRGBO(46, 54, 143, 1),
                        padding: EdgeInsets.all(15.0),
                        elevation: 1,
                      ),
                      SizedBox(
                        height: 10,
                      ),
                      Text(
                        'Add log',
                        style: kAddLogLabel,
                      )
                    ],
                  ),
                ),
              ]),
          list.isEmpty || chartData.isEmpty
              ? Expanded(
                  child: Center(
                    child: Text("No Log Data.."),
                  ),
                )
              : Expanded(
                  child: Column(
                    mainAxisSize: MainAxisSize.max,
                    children: <Widget>[
                      Container(
                        height: 150,
                        alignment: Alignment.center,
                        child: LineChartWidget(
                          list: chartData,
                          isDollar: true,
                        ),
                      ),
                      SizedBox(
                        height: 10,
                      ),
                      MultiSelectChip(
                        onSelectionChanged: (selectedList) async {
                          setState(() {
                            selectedItems = selectedList;
                          });
                          await Provider.of<LogProvider>(context, listen: false)
                              .filterLogList(selectedItems);
                        },
                      ),
                      MonthSelect(Color.fromRGBO(246, 246, 246, 1),
                          onMonthSelectionChanged: (selected) {
                        setState(() {
                          selectedMonth = selected;
                        });
                        selectedMonth == null
                            ? refreshData(currentMonth)
                            : refreshData(selectedMonth);
                      }),
                      Padding(
                        padding:
                            const EdgeInsets.only(top: 10, left: 0, right: 0),
                        child: Container(
                          width: double.infinity,
                          height: 1.0,
                          color: kDividerColor,
                        ),
                      ),

我所看到的是Multiselect芯片具有3次重绘/添加到列表 View 的相同项目列表,每次我进入NewLog屏幕时,列表都会不断增长

我目前在4个不同的屏幕上使用相同的窗口小部件,但是由于某些原因,当我导航到另一个屏幕时,列表会重置并显示原始项目,而重复的项目会消失

在屏幕外导航时,我该怎么做才能防止重新绘制

谢谢

最佳答案

您是否尝试过在listen: false中使用的Provider.of()中指定didChangeDependencies()?它可以解决问题。

但是,仍然存在风险。我怀疑初始化某事是否安全,因为当State对象的依存关系更改为其document中的书写时,将调用didChangeDependencies()。在initState()中执行此操作比较安全,或者只在外部执行一次,其结果传递给MultiSelectChip。

关于flutter - 跨多个屏幕使用的Flutter Stateful Widget得以重建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60785444/

相关文章:

dart - Flutter 在执行后台任务时显示 Progress HUD

android - 在 flutter 中下拉 ListView

firebase - Firestore 与其他用户共享数据

dart - 如何仅将填充应用于 Flutter 中 TextField 中的文本?

css - 如何在 Shiny 的滑动中更好地定位“下一个/后退”按钮,以消除大的空白区域?

javascript - 使用 MouseOver 事件控制 dijit.MenuBar

flutter - 滑动触发功能

App 仅支持移动设备纵向模式时的 Flutter 响应式设计(不支持 Web、平板电脑、桌面)

ios - 词法或预处理器问题 (Xcode) : 'Flutter/Flutter.h' file not found

flutter - 在脚手架主体中同时进行 2D 滚动(设计应用程序 miro 或 Figma)