Flutter:如何使用 GetX 查询列表项

Flutter: How to Query List Items using GetX

我正在尝试根据类别进行过滤,但它在每个类别页面上显示所有产品,但我想根据类别页面进行过滤,请检查我的代码并告诉我如何操作。

class CategoryNavigationController extends GetxController {

  final List<CategoryModel> _categories = allCategories;

  List<CategoryModel> get allCategory => _categories;

  int currentCategoryIndex;
  String currentCategoryTitle;
  List<Widget> totalCategoryTabs = [];
  List<ProductModel> _filtertedProducts;
  Widget currentTab;

  @override
  void onInit() {
    super.onInit();
    totalCategoryTabs = List.generate(allCategory.length, (index) {
      return ProductCardList(
        totalProducts: 1,
        productName: "WHy",
        productImage: "assets/images/chicken.png",
        price: "150",
        scrollDirection: Axis.vertical,
      );
    });
  }

  void selectCategory(int index) {
    currentCategoryIndex = index;
    currentCategoryTitle = allCategory[index].categoryName;
    _filterProductData(currentCategoryTitle);
    currentTab = totalCategoryTabs[index];
    Get.to(() => CategoryScreen());
    update();
  }

  void changeTab(int index) {
    currentCategoryIndex = index;
    currentCategoryTitle = allCategory[currentCategoryIndex].categoryName;
    _filterProductData(currentCategoryTitle);
    currentTab = totalCategoryTabs[currentCategoryIndex];
    update();
  }

  void _filterProductData(query) {
    print(query);
  }
}

这是我的数据模型。每次用户拖动选项卡视图或点击选项卡按钮时,我都想重建我当前的 TabView

class CategoryModel {
  String categoryName;
  String categoryImage;
  String categoryIcon;

  CategoryModel({
    this.categoryName,
    this.categoryImage,
    this.categoryIcon,
  });
}

List<CategoryModel> allCategories = <CategoryModel>[
  CategoryModel(
    categoryName: "Chicken",
    categoryImage: "assets/images/chicken.png",
    categoryIcon: "assets/svg/chicken.svg",
  ),
  CategoryModel(
    categoryName: "Fish",
    categoryImage: "assets/images/sea_fish.png",
    categoryIcon: "assets/svg/fish.svg",
  ),
  CategoryModel(
    categoryName: "Mutton",
    categoryImage: "assets/images/mutton.png",
    categoryIcon: "assets/svg/mutton.svg",
  ),
  CategoryModel(
    categoryName: "Marinade",
    categoryImage: "assets/images/marinade.png",
    categoryIcon: "assets/svg/premium_meat.svg",
  ),
  CategoryModel(
    categoryName: "Cold Cut",
    categoryImage: "assets/images/sea_fish.png",
    categoryIcon: "assets/svg/cold_cut.svg",
  ),
  CategoryModel(
    categoryName: "Prone",
    categoryImage: "assets/images/sea_fish.png",
    categoryIcon: "assets/svg/fish.svg",
  ),
];

class ProductModel {
  String productName;
  String productImage;
  CategoryModel category;
  String price;
  String stock;

  ProductModel({
    this.productName,
    this.category,
    this.price,
    this.stock,
    this.productImage,
  });
}

List<ProductModel> allProducts = <ProductModel>[
  ProductModel(
    category: allCategories[0],
    productName: "chicken1",
    productImage: "assets/images/chicken.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[0],
    productName: "chicken2",
    productImage: "assets/images/chicken.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[1],
    productName: "fish1",
    productImage: "assets/images/fish.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[1],
    productName: "fish2",
    productImage: "assets/images/fish.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[2],
    productName: "mutton1",
    productImage: "assets/images/mutton.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[2],
    productName: "mutton2",
    productImage: "assets/images/mutton.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[3],
    productName: "marinade1",
    productImage: "assets/images/marinade.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[3],
    productName: "marinade2",
    productImage: "assets/images/marinade.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[4],
    productName: "ColdCut1",
    productImage: "assets/images/sea_fish.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[4],
    productName: "ColdCut2",
    productImage: "assets/images/sea_fish.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[5],
    productName: "prone1",
    productImage: "assets/images/sea_fish.png",
    price: "150",
  ),
  ProductModel(
    category: allCategories[5],
    productName: "prone2",
    productImage: "assets/images/sea_fish.png",
    price: "150",
  ),
];

这是我的类别屏幕,我在其中使用了 TabBar 和 TabView。

GetBuilder<CategoryNavigationController>(
      builder: (controller) => Scaffold(
        appBar: AppBar(
          toolbarHeight: AppConfig.screenHeight(context) * 0.06,
          centerTitle: true,
          elevation: 0,
          backgroundColor: Colors.white,
          title: Text(
            "MENU",
            style: TextStyle(
              color: Color(0xff1F1F1F),
              fontWeight: FontWeight.w600,
              fontStyle: FontStyle.normal,
            ),
          ),
        ),
        body: DefaultTabController(
          initialIndex: controller.currentCategoryIndex,
          length: controller.allCategory.length,
          child: Container(
            width: double.infinity,
            height: double.infinity,
            child: Column(
              children: [
                Container(
                  height: AppConfig.screenHeight(context) * 0.1,
                  decoration: BoxDecoration(
                    border: Border(
                      bottom: BorderSide(
                        color: AppConfig.disableColor,
                        width: 1,
                      ),
                    ),
                    boxShadow: [
                      BoxShadow(
                        color: AppConfig.disableColor.withOpacity(0.5),
                        offset: Offset(0, 1),
                        spreadRadius: 1,
                        blurRadius: 1,
                      ),
                    ],
                    color: Colors.white,
                  ),
                  child: TabBar(
                    controller: controller.tabController,
                    onTap: (index) {
                      controller.changeTab();
                    },
                    isScrollable: true,
                    indicator: BoxDecoration(
                      color: AppConfig.disableColor,
                      border: Border(
                        bottom: BorderSide(
                          color: AppConfig.primaryColor,
                        ),
                      ),
                    ),
                    tabs: List.generate(
                      controller.allCategory.length,
                      (index) {
                        return CategoryButtons(
                          buttonIcon: SvgPicture.asset(
                            controller.allCategory[index].categoryIcon,
                            width: AppConfig.screenWidth(context) * 0.085,
                          ),
                          buttonName:
                              controller.allCategory[index].categoryName,
                        );
                      },
                    ),
                  ),
                ),
                Expanded(
                  child: TabBarView(
                    controller: controller.tabController,
                    children:
                        controller.allCategory.map((CategoryModel category) {
                      return controller.currentTab;
                    }).toList(),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );

好的,首先,让我们解决这个问题:

final List<CategoryModel> _categories = allCategories;

List<CategoryModel> get allCategory => _categories;

这没有做任何有价值的事情。您正在声明一个私有变量并将其初始化为顶级全局变量。然后使用 public getter 再次访问一个私有变量,它只不过是你已经声明的全局变量。

这里有两件事。

  1. 我与其他语言相比,在 Dart 中,there's nothing to be gained 使用 getters 和 setter,UNLESS,你正在添加自定义逻辑以获取或设置值。

  2. allCategories 列表没有必要是全局的。您可以将它放在 GetX class 中,并且仍然可以从应用程序的任何位置轻松访问它。因此,让我们简化一下,只需将该列表放入 class 并删除 getter 即可。现在它是一个变量而不是 3 个。

一般来说,除非有充分的理由将某些东西全球化,否则最好不要这样做。

至于实际解决方案。有不同的方法可以实现这一点,但我会这样做:

我不是通过列表过滤并每次都重建所有内容,而是为每个类别设置一个单独的列表,然后 addProduct 函数根据类别将其添加到正确的列表中。这样,唯一重建的就是相应的选项卡。我留下了一个主产品列表,以防您需要它来做其他事情,但它没有用于我在这里做的任何事情。

  List<ProductModel> masterProductList = [];

  List<ProductModel> chickenList = [];
  List<ProductModel> fishList = [];
  List<ProductModel> muttonList = [];
  List<ProductModel> marinadeList = [];
  List<ProductModel> coldCutList = [];
  List<ProductModel> proneList = [];

另外,该功能是利用tabController(貌似你去掉了,我又放回去了)跳转到相应的tab。这可能是也可能不是所需的行为,但它只是向您展示一种使用 Getx 管理选项卡的超级简单方法。 animateTo 功能不是 GetX 特有的,但可以轻松地在整个应用程序中共享一个选项卡控制器。这是 GetX class.

中的 addProduct 函数

如果您有一些我不知道的大量产品列表,您仍然可以遍历它并通过此函数传递所有内容,它会对其进行排序。

void addProduct(ProductModel product) {
    masterProductList.add(product);
    switch (product.category.categoryName) {
      case 'Chicken':
        chickenList.add(product);
        tabController.animateTo(0); // this jumps to whatever tab you want based on the index you pass in
        break;
      case 'Fish':
        fishList.add(product);
        tabController.animateTo(1);
        break;
      case 'Mutton':
        muttonList.add(product);
        tabController.animateTo(2);
        break;
      case 'Marinade':
        marinadeList.add(product);
        tabController.animateTo(3);
        break;
      case 'Cold Cut':
        coldCutList.add(product);
        tabController.animateTo(4);
        break;
      case 'Prone':
        proneList.add(product);
        tabController.animateTo(5);
        break;
    }
    update();
  }

由于我没有你所有的 UI 代码,这里有一个非常简化的版本来向你展示它是如何工作的。您可以根据自己的喜好将此实现到您的应用程序中。

这是 TabHome。这里什么都没有重建,它只是选项卡的主机。 GetView<CategoryNavigationController> 只是一个无状态的小部件,它使我们不必在该页面上找到该控制器。

class TabHome extends GetView<CategoryNavigationController> {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: controller.allCategories.length,
      child: Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            tabs: controller.totalCategoryTabs,
            controller: controller.tabController,
          ),
          title: Text('Categories'),
        ),
        body: TabBarView(
          controller: controller.tabController,
          children: [
            ProductPage(list: controller.chickenList), // passing in corresponding list from GetX class
            ProductPage(list: controller.fishList),
            ProductPage(list: controller.muttonList),
            ProductPage(list: controller.marinadeList),
            ProductPage(list: controller.coldCutList),
            ProductPage(list: controller.proneList),
          ],
        ),
      ),
    );
  }
}

这是一个非常基本的产品页面,它被传递到一个列表中,该列表被传递到 GetBuilder 小部件中的 ListView.builder

class ProductPage extends StatelessWidget {
  final List list;

  const ProductPage({Key key, this.list}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          GetBuilder<CategoryNavigationController>(
            builder: (controller) => Expanded(
              child: ListView.builder(
                itemCount: list.length,
                itemBuilder: (context, index) => ProductRow(product: list[index]),
              ),
            ),
          ),
          ButtonRow(),
        ],
      ),
    );
  }
}

非常基本 Row 需要 ProductModel

class ProductRow extends StatelessWidget {
  final ProductModel product;

  const ProductRow({Key key, this.product}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Row(children: [Text(product.productName)]);
  }
}

您在 ProductPage 中看到的 ButtonRow 是一个小部件,其中有 6 个小部件,每个都添加来自不同类别的产品,调用相同的 addProduct 函数,但添加了不同的产品。

 Expanded(
              child: ElevatedButton(
                onPressed: () {
                  controller.addProduct(
                    ProductModel(
                      productName: 'boneless chicken',
                      category: CategoryModel(categoryName: 'Chicken'),
                    ),
                  );
                },
                child: Text('Add chicken'),
              ),
            ),

最后,对您的 onInit 进行一些小改动。请务必将 with SingleGetTickerProviderMixin 添加到您的 GetX class,这样您就可以在无状态小部件中使用动画和选项卡控制器。

  @override
  void onInit() {
    super.onInit();
    totalCategoryTabs = List.generate(allCategories.length, (index) {
      return ProductCardList(
        totalProducts: 1,
        productName: allCategories[index].categoryName, // auto names your tabs based on allCategories list
        productImage: "assets/images/chicken.png",
        price: "150",
        scrollDirection: Axis.vertical,
      );
    });
    tabController =
        TabController(length: totalCategoryTabs.length, vsync: this); // made possible with SingleGetTickerProviderMixin 
  }

这是一个快速演示。 GUI不性感,但你懂的。