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 再次访问一个私有变量,它只不过是你已经声明的全局变量。
这里有两件事。
我与其他语言相比,在 Dart 中,there's nothing to be gained 使用 getters 和 setter,UNLESS,你正在添加自定义逻辑以获取或设置值。
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不性感,但你懂的。
我正在尝试根据类别进行过滤,但它在每个类别页面上显示所有产品,但我想根据类别页面进行过滤,请检查我的代码并告诉我如何操作。
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 再次访问一个私有变量,它只不过是你已经声明的全局变量。
这里有两件事。
我与其他语言相比,在 Dart 中,there's nothing to be gained 使用 getters 和 setter,UNLESS,你正在添加自定义逻辑以获取或设置值。
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不性感,但你懂的。