Flutter игнорирует оператор return внутри ветки «if»

#flutter #if-statement #dart #return

#flutter #if-statement #dart #Возврат

Вопрос:

Я пытаюсь создать фильтр из списка объектов, используя виджет PopupMenuButton. Я думаю, что логика правильная, но Flutter / Dart, похоже, игнорирует оператор return внутри ветки «if» в моей функции с именем «fliterFavs» в приведенном ниже фрагменте кода.

Когда я выбираю «Избранное», оно распознается как ожидалось, и оператор печати перед возвратом работает нормально.

Когда я использую тот же самый оператор return вместо того, который находится вне оператора if, он работает нормально. Я получаю обратно отфильтрованный набор данных, который я ожидаю.

Я даже пробовал его как два спина к спине, если операторы, вместо вложенного, который вы видите ниже. Он по-прежнему не работает.

есть идеи?

 final List<Product> favProducts = [];

  Widget filterFavs(value) {
    loadedProducts.forEach((i) {
      if (i.isFavorite == true) {
        favProducts.add(i);
        if (value == "Favs") {
          print(value);
          return buildGrid(favProducts);
        }
      }
    });
    return buildGrid(loadedProducts);
  }

  Widget buildGrid(List newList) {
    return GridView.builder(
      padding: const EdgeInsets.all(10.0),
      itemCount: newList.length,
      itemBuilder: (ctx, i) => ProductItem(
        newList[i].id,
        newList[i].title,
        newList[i].imageUrl,
      ),
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        childAspectRatio: 3 / 2,
        crossAxisSpacing: 10,
        mainAxisSpacing: 10,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('MyShop'),
          actions: <Widget>[
            PopupMenuButton(
              onSelected: (val) {
                filterFavs(val);
              },
              icon: Icon(
                Icons.more_vert,
              ),
              itemBuilder: (context) => [
                PopupMenuItem(
                  child: Text("Favs"),
                  value: "Favs",
                ),
                PopupMenuItem(
                  child: Text("All"),
                  value: "All",
                ),
              ],
            ),
          ],
        ),
        //use a filter on the item builder
        body: filterFavs(context));
  }
}

  

Ответ №1:

Подумайте о функции, из которой возвращается возврат, на который вы ссылаетесь. Он возвращается к анонимной функции, переданной forEach методу, а не filterFavs так, как вы ожидаете. Это не проблема с flutter / dart, это проблема с вашими ожиданиями.

Вы можете использовать альтернативный синтаксис for-each для решения этой проблемы:

 Widget filterFavs(value) {
  for(var i in loadedProducts) {
    if (i.isFavorite == true) {
      favProducts.add(i);
      if (value == "Favs") {
        print(value);
        return buildGrid(favProducts);
      }
    }
  }
  return buildGrid(loadedProducts);
}
  

Комментарии:

1. Спасибо за быстрый ответ. Кажется логичным. Он по-прежнему не работает. То же поведение

2. @ctacta1 Что значит «не работает»? Мне очень трудно поверить, что они будут иметь одинаковое поведение.

3. Тот же результат… Я выбираю «Избранное» через PopupMenuItem через значок «more_vert» на панели приложений… «Favs» возвращается из метода print, но страница по-прежнему отображает «ВСЕ» экземпляры, а НЕ ТОЛЬКО те, где «i.isFavorite == true»… таким образом, продолжает возвращаться: return buildGrid(loadedProducts); вместо return buildGrid(favProducts); Очевидно, что в моем коде что-то еще не так

4. @ctacta1 Вы используете этот метод очень странно. Почему вы делаете body: filterFavs(context)

5. Как я сейчас смотрю на это, это отличный вопрос. Я думаю, что моя проблема заключается в этом. Все, что я пытаюсь сделать, это создать фильтр, в котором пользователь может использовать подмножество продуктов, которые он / она получает для возврата. Но похоже, что свойство body не видит вывод buildGrid() . Не знаю.

Ответ №2:

Кристофер Мур спасибо за вашу помощь, вот окончательное решение, которое теперь работает.

 import 'package:flutter/material.dart';

import '../models/product.dart';
import '../widgets/product_item.dart';

class ProductsOverviewScreen extends StatefulWidget {
  @override
  _ProductsOverviewScreenState createState() => _ProductsOverviewScreenState();
}

class _ProductsOverviewScreenState extends State<ProductsOverviewScreen> {
  List choices = ["Favs", "All"];
  String _choice = '';

  void _select(userChoice) {
    setState(() {
      _choice = userChoice;
      print(_choice);
    });
  }

  final List<Product> loadedProducts = [
    Product(
      id: 'p1',
      title: 'Red Shirt',
      description: 'A red shirt - it is pretty red!',
      price: 29.99,
      isFavorite: true,
      imageUrl:
          'https://cdn.pixabay.com/photo/2016/10/02/22/17/red-t-shirt-1710578_1280.jpg',
    ),
    Product(
      id: 'p2',
      title: 'Trousers',
      description: 'A nice pair of trousers.',
      price: 59.99,
      isFavorite: true,
      imageUrl:
          'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Trousers,_dress_(AM_1960.022-8).jpg/512px-Trousers,_dress_(AM_1960.022-8).jpg',
    ),
    Product(
      id: 'p3',
      title: 'Yellow Scarf',
      description: 'Warm and cozy - exactly what you need for the winter.',
      price: 19.99,
      isFavorite: false,
      imageUrl:
          'https://live.staticflickr.com/4043/4438260868_cc79b3369d_z.jpg',
    ),
    Product(
      id: 'p4',
      title: 'A Pan',
      description: 'Prepare any meal you want.',
      price: 49.99,
      isFavorite: false,
      imageUrl:
          'https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Cast-Iron-Pan.jpg/1024px-Cast-Iron-Pan.jpg',
    ),
  ];

  List<Product> favProducts = [];

  Widget filterFavs(value) {
    if (favProducts.isEmpty) {
      // this is to prevent items from being infinitely added to favProducts
      //if user selects Favs more than once
      for (var i in loadedProducts) {
        if (i.isFavorite == true) {
          favProducts.add(i);
        }
      }
    }
    if (value == "Favs") {
      print(value);
      return buildGrid(favProducts);
    }
    favProducts = [];
    return buildGrid(loadedProducts);
  }

  Widget buildGrid(List newList) {
    return GridView.builder(
      padding: const EdgeInsets.all(10.0),
      itemCount: newList.length,
      itemBuilder: (ctx, i) => ProductItem(
        newList[i].id,
        newList[i].title,
        newList[i].imageUrl,
      ),
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        childAspectRatio: 3 / 2,
        crossAxisSpacing: 10,
        mainAxisSpacing: 10,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('MyShop'),
          actions: <Widget>[
            PopupMenuButton(
                elevation: 3.2,
                initialValue: choices[1],
                onSelected: _select,
                icon: Icon(
                  Icons.more_vert,
                ),
                itemBuilder: (context) => [
                      PopupMenuItem(
                        child: Text(choices[0]),
                        value: choices[0],
                      ),
                      PopupMenuItem(
                        child: Text(choices[1]),
                        value: choices[1],
                      ),
                    ]),
          ],
        ),
        //use a filter on the item builder
        body: filterFavs(_choice));
  }
}