为什么有状态小部件无法在颤动中保持其状态

时间:2021-07-04 04:39:49

标签: android flutter dart stateful dropdownbutton

在我的程序中,我放置了添加按钮来创建带有状态下拉按钮的有状态框,每次添加框时,我都会将其添加到 Map 并将其传递给列。当我单击十字按钮时,它会从父级地图中删除小部件。但是当我点击小部件上的十字按钮时,它显示了错误的框颜色和错误的下拉值。观看我发布的 GIF 以了解问题的概述

enter image description here

链接到飞镖板以运行示例:dart pad code link here

import 'package:flutter/material.dart';
import 'dart:math';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  _StateMyWidget createState() => _StateMyWidget();
}

class _StateMyWidget extends State<MyWidget> {
  Map<int, Widget> widgetList = {};
  int boxCount = 0;

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

  @override
  Widget build(BuildContext context) {
    return ListView(children: [
      Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Column(
              mainAxisSize: MainAxisSize.min,
              children: widgetList.values.toList()),
          TextButton(
              onPressed: () {
                widgetList[boxCount] =
                    new MyBox(boxIndex: boxCount, deleteFunction: deleteBox);
                setState(() {});
                boxCount += 1;
              },
              child: Text("Add"))
        ],
      )
    ]);
  }

  deleteBox(boxIndex) {
    widgetList.remove(boxIndex);
    setState(() {});
  }
}

class MyBox extends StatefulWidget {
  final int boxIndex;
  final Function deleteFunction;
  MyBox({required this.boxIndex, required this.deleteFunction});
  _StateMyBox createState() => _StateMyBox();
}

class _StateMyBox extends State<MyBox> {
  var containerColor;
  @override
  initState() {
    super.initState();
    containerColor =
        Colors.primaries[Random().nextInt(Colors.primaries.length)];
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        width: 200,
        height: 200,
        margin: EdgeInsets.all(17),
        padding: EdgeInsets.all(10),
        color: containerColor,
        child: Column(children: [
          Row(children: [
            Text("Box Number: ${widget.boxIndex}"),
            Spacer(),
            IconButton(
              icon: const Icon(Icons.clear),
              onPressed: () {
                widget.deleteFunction(widget.boxIndex);
              },
            ),
          ]),
          RegistrationDropdown(listData: ['One', 'Two', 'Three', 'Four']),
        ]));
  }
}

class RegistrationDropdown extends StatefulWidget {
  final List<String> listData;
  RegistrationDropdown({
    required this.listData,
  });
  @override
  _StateRegistrationDropdown createState() {
    return _StateRegistrationDropdown();
  }
}

class _StateRegistrationDropdown extends State<RegistrationDropdown> {
  String dropdownValue = 'One';
  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.white,
        padding: EdgeInsets.only(left: 10, right: 10),
        child: DropdownButton<String>(
          isExpanded: true,
          underline: SizedBox(),
          value: dropdownValue,
          icon: const Icon(Icons.arrow_downward),
          iconSize: 24,
          elevation: 16,
          style: const TextStyle(color: Colors.deepPurple),
          onChanged: (String? newValue) {
            print("Previous dropdown value $dropdownValue");
            print("New value $newValue");
            setState(() {
              dropdownValue = newValue!;
            });
          },
          items: widget.listData.map<DropdownMenuItem<String>>((String value) {
            return DropdownMenuItem<String>(
              value: value,
              child: Text(value),
            );
          }).toList(),
        ));
  }
}

1 个答案:

答案 0 :(得分:1)

解决方案是小部件的 KeyWhen to Use Keys: Flutter Youtube 会很有帮助。

import 'package:flutter/material.dart';
import 'dart:math';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  _StateMyWidget createState() => _StateMyWidget();
}

class _StateMyWidget extends State<MyWidget> {
  Map<int, Widget> widgetList = {};
  int boxCount = 0;

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

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Column(
              mainAxisSize: MainAxisSize.min,
              children: widgetList.values.toList(),
            ),
            TextButton(
              onPressed: () {
                widgetList[boxCount] = new MyBox(
                  key: UniqueKey(), // <---------------------
                  boxIndex: boxCount,
                  deleteFunction: deleteBox,
                );
                setState(() {});
                boxCount += 1;
              },
              child: Text("Add"),
            )
          ],
        )
      ],
    );
  }

  deleteBox(boxIndex) {
    widgetList.remove(boxIndex);
    setState(() {});
  }
}

class MyBox extends StatefulWidget {
  final int boxIndex;
  final Function deleteFunction;

  MyBox({
    Key? key, // <---------------------
    required this.boxIndex,
    required this.deleteFunction,
  }) : super(key: key); // <---------------------

  _StateMyBox createState() => _StateMyBox();
}

class _StateMyBox extends State<MyBox> {
  var containerColor;
  @override
  initState() {
    super.initState();
    containerColor =
        Colors.primaries[Random().nextInt(Colors.primaries.length)];
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        width: 200,
        height: 200,
        margin: EdgeInsets.all(17),
        padding: EdgeInsets.all(10),
        color: containerColor,
        child: Column(children: [
          Row(children: [
            Text("Box Number: ${widget.boxIndex}"),
            Spacer(),
            IconButton(
              icon: const Icon(Icons.clear),
              onPressed: () {
                widget.deleteFunction(widget.boxIndex);
              },
            ),
          ]),
          RegistrationDropdown(listData: ['One', 'Two', 'Three', 'Four']),
        ]));
  }
}

class RegistrationDropdown extends StatefulWidget {
  final List<String> listData;
  RegistrationDropdown({
    required this.listData,
  });
  @override
  _StateRegistrationDropdown createState() {
    return _StateRegistrationDropdown();
  }
}

class _StateRegistrationDropdown extends State<RegistrationDropdown> {
  String dropdownValue = 'One';
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      padding: EdgeInsets.only(left: 10, right: 10),
      child: DropdownButton<String>(
        isExpanded: true,
        underline: SizedBox(),
        value: dropdownValue,
        icon: const Icon(Icons.arrow_downward),
        iconSize: 24,
        elevation: 16,
        style: const TextStyle(color: Colors.deepPurple),
        onChanged: (String? newValue) {
          print("Previous dropdown value $dropdownValue");
          print("New value $newValue");
          setState(() {
            dropdownValue = newValue!;
          });
        },
        items: widget.listData.map<DropdownMenuItem<String>>((String value) {
          return DropdownMenuItem<String>(
            value: value,
            child: Text(value),
          );
        }).toList(),
      ),
    );
  }
}