无法将数据传递到下一个屏幕,因为选择状态未知

Can't pass data to next screen because selection state is unknown

我正在开发这个应用程序,它应该可以告诉您可以搭配您目前正在享用的特定餐点或葡萄酒的哪种酒或餐点。我目前正处于让用户能够搜索 wine/meal 的阶段,他或她目前很乐意询问 his/her 侍酒师什么 wine/meal 最合适。现在我的结构如下所示:用户打开屏幕,他看到 wines/meals 中的一个 ListView.builder 他可以从中选择,但不排除之前的选择(类型...)。现在我实现了一个搜索,它使用从 firebase 数据创建一个有状态列表变量的事实,然后能够搜索列表并显示结果。现在为了显示这些结果,我写了一个名为 PrefInformationCard 的小部件,它基本上是一张显示所有相关数据的卡片......现在向用户指示点击的卡片 he/she 已被选中,我实现了一个布尔值检查更改小部件的颜色。这有两个问题。我在小部件中实现了它,这意味着在屏幕和列表视图构建器中,我不知道是否选择了一张卡片以及选择了什么卡片,所以我无法将所选数据传递到下一个屏幕。现在的另一个问题是,有可能一次选择多张卡片。

在第一个文档中,您将看到第 4 步屏幕的代码:

class AskSomellierStep4Screen extends StatefulWidget {
  const AskSomellierStep4Screen({
    Key? key,
    required this.stepDescription,
    required this.wineOrMeal,
    required this.mealVSWine,
    required this.selectedCuisine,
  }) : super(key: key);

  final String wineOrMeal;
  final String stepDescription;
  final bool mealVSWine;
  final String selectedCuisine;

  @override
  State<AskSomellierStep4Screen> createState() =>
      _AskSomellierStep4ScreenState();
}

class _AskSomellierStep4ScreenState extends State<AskSomellierStep4Screen> {
  List<String> dataLabel = [
    'Home',
    'Search',
    'Account',
  ];
  late Future resultsLoaded;
  List<IconData> data = [
    CustomIcons.home,
    CustomIcons.search,
    CustomIcons.user,
  ];

  getResults() async {
    var data = await FirebaseFirestore.instance
        .collection(widget.wineOrMeal)
        .where('type', isEqualTo: widget.selectedCuisine)
        .get();
    setState(() {
      allResults = data.docs;
    });
    filterResultsList();
    return data.docs;
  }

  List allResults = [];

  List filteredResults = [];

  onSearchChanged() {
    print(searchController.text);
    filterResultsList();
  }

  filterResultsList() {
    var showResults = [];

    if (searchController.text != '') {
      // we have a search parameter
      for (var searchSnapshot in allResults) {
        var name = searchSnapshot['name'].toLowerCase();

        if (name.contains(searchController.text.toLowerCase())) {
          showResults.add(searchSnapshot);
        }
      }
    } else {
      // we do not have a search parameter
      showResults = List.from(allResults);
    }
    setState(() {
      filteredResults = showResults;
    });
  }

  TextEditingController searchController = TextEditingController();

  @override
  void initState() {
    super.initState();
    searchController.addListener(onSearchChanged);
  }

  @override
  void dispose() {
    searchController.removeListener(onSearchChanged);
    searchController.dispose();
    super.dispose();
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    resultsLoaded = getResults();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).scaffoldBackgroundColor,
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          HomeScreenHeader(
            subText: 'Wine and Food',
            mainText: 'Ask your Somellier',
            boxWidth: 238,
          ),
          Padding(
            padding: const EdgeInsets.only(
              left: 172,
              top: 92,
            ),
            child: Text(
              'Step 4',
              style: GoogleFonts.poppins(
                textStyle: TextStyle(
                  color: Theme.of(context).indicatorColor,
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(
              left: 97,
            ),
            child: Text(
              widget.stepDescription,
              style: GoogleFonts.poppins(
                textStyle: TextStyle(
                  color: Theme.of(context).primaryColorLight,
                  fontSize: 14,
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(
              left: 35,
              top: 25,
            ),
            child: Stack(
              children: [
                Container(
                  height: 35,
                  width: 320,
                  decoration: BoxDecoration(
                    color: Theme.of(context).primaryColor,
                    borderRadius: BorderRadius.circular(20.0),
                  ),
                ),
                Positioned(
                  left: 10,
                  top: 14.5,
                  child: SizedBox(
                    height: 21,
                    width: 300,
                    child: TextField(
                      controller: searchController,
                      style: GoogleFonts.poppins(
                          textStyle: const TextStyle(
                              color: Colors.white,
                              fontSize: 14,
                              fontWeight: FontWeight.bold)),
                      decoration: InputDecoration(
                        hintText: 'Search',
                        hintStyle: GoogleFonts.poppins(
                          textStyle: TextStyle(
                              color: Theme.of(context).hintColor,
                              fontSize: 16,
                              fontWeight: FontWeight.bold),
                        ),
                        border: InputBorder.none,
                      ),
                    ),
                  ),
                ),
                Positioned(
                  left: 320 - 35,
                  top: 119 - 110,
                  child: SizedBox(
                    height: 17,
                    width: 17,
                    child: SvgPicture.asset(
                      'assets/icons/general/search.svg',
                      color: Theme.of(context).indicatorColor,
                    ),
                  ),
                ),
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(
              left: 35,
              top: 15,
            ),
            child: Text(
              'Popular Choices',
              style: GoogleFonts.poppins(
                textStyle: const TextStyle(
                  color: Colors.white,
                  fontSize: 14,
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(
              left: 35,
              top: 5,
            ),
            child: SizedBox(
              height: 370,
              width: 320,
              child: Center(
                child: ListView.builder(
                  dragStartBehavior: DragStartBehavior.down,
                  scrollDirection: Axis.vertical,
                  itemCount: filteredResults.length,
                  itemBuilder: (context, index) => widget.mealVSWine
                      ? PrefInformationCardWine(
                          snapShotDocument: filteredResults[index],
                          cardColor: Theme.of(context).primaryColor,
                          selected: false,
                        )
                      : PrefInformationCardMeal(
                          snapshotDocument: filteredResults[index],
                          cardColor: Theme.of(context).primaryColor,
                          selected: false),
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(
              left: 35,
              top: 25,
            ),
            child: SubmitSettingChangesButton(
              buttonText: 'Continue',
              cancelText: 'Cancel',
              cancelOnTap: () {
                Navigator.pop(context);
              },
              continueOnTap: () {
                Navigator.pushAndRemoveUntil(
                    context,
                    createRoute(FindingRecommendationScreen()),
                    (route) => false);
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(
              top: 15,
              left: 171,
            ),
            child: GestureDetector(
              onTap: () {
                Navigator.pop(context);
              },
              child: SizedBox(
                height: 16,
                width: 47,
                child: Center(
                  child: Text(
                    'Go Back',
                    style: GoogleFonts.poppins(
                      textStyle: TextStyle(
                        color: Theme.of(context).indicatorColor,
                        fontSize: 11,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

这是 PrefInformationCard 的相关代码:

class PrefInformationCardWine extends StatefulWidget {
  PrefInformationCardWine({
    Key? key,
    required this.snapShotDocument,
    required this.cardColor,
    required this.selected,
  }) : super(key: key);

  DocumentSnapshot snapShotDocument;
  Color cardColor;
  bool selected;

  @override
  State<PrefInformationCardWine> createState() =>
      _PrefInformationCardWineState();
}

class _PrefInformationCardWineState extends State<PrefInformationCardWine> {
  Color backgroundColor(context, selected) {
    setState(() {
      if (widget.selected == true) {
        widget.cardColor = Theme.of(context).primaryColorLight;
      } else {
        widget.cardColor = Theme.of(context).primaryColor;
      }
    });
    return widget.cardColor;
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(
        bottom: 25,
      ),
      child: GestureDetector(
        onTap: () {
          setState(() {
            widget.selected = !widget.selected;
          });
        },
        child: Stack(
          children: [
            Container(
              height: 185,
              width: 320,
              decoration: BoxDecoration(
                color: backgroundColor(context, widget.selected),
                boxShadow: [
                  BoxShadow(
                    offset: const Offset(0, 4),
                    color: const Color(0xff000000).withOpacity(.25),
                  ),
                ],
                borderRadius: BorderRadius.circular(
                  35,
                ),
              ),
            ),
...

如果有人能帮我解决这个问题,我会很高兴,因为坦率地说,我不知道如何解决这个问题。提前谢谢你:)


Padding(
            padding: const EdgeInsets.only(
              left: 35,
              top: 25,
            ),
            child: SubmitSettingChangesButton(
              buttonText: 'Continue',
              cancelText: 'Cancel',
              cancelOnTap: () {
                Navigator.pop(context);
              },
              continueOnTap: () {
                Navigator.pushAndRemoveUntil(
                    context,
                    createRoute(FindingRecommendationScreen(
                      snapshotName: _selectedSnapshot,
                    )),
                    (route) => false);
              },
            ),
          ),

这就是我想要传递数据的方式

与其在卡片中处理所选状态,不如在第 4 步屏幕中使用回调来设置状态。

(这将重建整个第 4 步屏幕,但我不确定仅使用 setState 的另一种方法)

例如:

  late DocumentSnapshot _selectedSnapshot;
  final List filteredResults = [];
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 370,
      width: 320,
      child: Center(
        child: ListView.builder(
          dragStartBehavior: DragStartBehavior.down,
          scrollDirection: Axis.vertical,
          itemCount: filteredResults.length,
          itemBuilder: (context, index) => widget.mealVSWine
              ? PrefInformationCardWine(
                  snapShotDocument: filteredResults[index],
                  cardColor: Theme.of(context).primaryColor,
                  isSelected: filteredResults[index] == _selectedSnapshot,
                  onSelected: () {
                    setState(() {
                      _selectedSnapshot = filteredResults[index];
                    });
                  },
                )
              : PrefInformationCardMeal(
                  snapshotDocument: filteredResults[index],
                  cardColor: Theme.of(context).primaryColor,
                  isSelected: filteredResults[index] == _selectedSnapshot,
                  onSelected: () {
                    setState(() {
                      _selectedSnapshot = filteredResults[index];
                    });
                  },
                ),
        ),
      ),
    );
  }
}

那么在你的卡片中:


class PrefInformationCardWine extends StatefulWidget {
  PrefInformationCardWine({
    Key? key,
    required this.snapShotDocument,
    required this.cardColor,
    required this.isSelected,
    required this.onSelected,
  }) : super(key: key);

  DocumentSnapshot snapShotDocument;
  Color cardColor;
  bool isSelected;
  VoidCallback onSelected;

  @override
  State<PrefInformationCardWine> createState() =>
      _PrefInformationCardWineState();
}

class _PrefInformationCardWineState extends State<PrefInformationCardWine> {
  Color backgroundColor(context, selected) {
    setState(() {
      if (widget.isSelected == true) {
        widget.cardColor = Theme.of(context).primaryColorLight;
      } else {
        widget.cardColor = Theme.of(context).primaryColor;
      }
    });
    return widget.cardColor;
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(
        bottom: 25,
      ),
      child: GestureDetector(
        onTap: widget.onSelected,
        child: Stack(
          children: [
            Container(
              height: 185,
              width: 320,
              decoration: BoxDecoration(
                color: backgroundColor(context, widget.isSelected),
                boxShadow: [
                  BoxShadow(
                    offset: const Offset(0, 4),
                    color: const Color(0xff000000).withOpacity(.25),
                  ),
                ],
                borderRadius: BorderRadius.circular(
                  35,
                ),
              ),
            )
...