Flutter: как запрашивать элементы списка с помощью GetX
Я пытаюсь фильтровать по категории, но на каждой странице категории отображаются все продукты, но я хочу фильтровать по странице категории, пожалуйста, проверьте мой код и дайте мне знать, как я могу это сделать.
class CategoryNavigationController extends GetxController {
TabController tabController;
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);
}
}
1 ответ
Хорошо, для начала давайте рассмотрим это:
final List<CategoryModel> _categories = allCategories;
List<CategoryModel> get allCategory => _categories;
Это не делает ничего ценного. Вы объявляете частную переменную и инициализируете ее глобальной переменной верхнего уровня. Затем использование общедоступного геттера для доступа к частной переменной, которая снова является не чем иным, как уже объявленной вами глобальной переменной.
Итак, здесь 2 вещи.
Я контрастирую с другими языками, в Dart ничего не получится от использования геттеров и сеттеров, ЕСЛИ вы не добавляете настраиваемую логику для получения или установки значения.
Нет причин, по которым
allCategories
список должен быть глобальным. Вы можете просто поместить его в класс GetX, и он по-прежнему очень легко доступен из любой точки приложения. Так что давайте упростим это и просто поместим этот список в класс и потеряем геттеры. Теперь это одна переменная вместо трех.
Как правило, лучше не делать этого, если нет веской причины сделать что-то глобальное.
Что касается фактического решения. Есть разные способы добиться этого, но я бы сделал это следующим образом:
Вместо того, чтобы фильтровать список и перестраивать все каждый раз, я просто настраиваю отдельный список для каждой категории, и функция добавляет его в нужный список в зависимости от категории. Таким образом, единственное, что будет перестроено, - это соответствующая вкладка. Я оставил основной список продуктов на случай, если он понадобится вам для чего-то еще, но он не используется ни для чего, что я здесь делаю.
List<ProductModel> masterProductList = [];
List<ProductModel> chickenList = [];
List<ProductModel> fishList = [];
List<ProductModel> muttonList = [];
List<ProductModel> marinadeList = [];
List<ProductModel> coldCutList = [];
List<ProductModel> proneList = [];
Кроме того, функция использует
tabController
(который выглядит так, как будто вы удалили, но я вернул его), чтобы перейти на соответствующую вкладку. Это может быть, а может и не быть желаемым поведением, но это просто показать вам очень простой способ управления вкладками с помощью Getx. В
animateTo
функция не является специфической для GetX, но легко разделять контроллер вкладок во всем вашем приложении. Вот функция, которая входит в ваш класс GetX.
Если у вас есть обширный список продуктов, о котором я не знаю, вы все равно можете просмотреть его и передать все через эту функцию, и она отсортирует его.
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();
}
Поскольку у меня нет всего вашего кода пользовательского интерфейса, вот значительно упрощенная версия, чтобы показать вам, как это работает. Вы можете реализовать это в своем приложении, как считаете нужным.
Вот
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),
],
),
),
);
}
}
Вот очень простая страница продукта, которая передается в виде списка, который передается в
ListView.builder
в пределах
GetBuilder
виджет.
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)]);
}
}
В
ButtonRow
что вы видите в
ProductPage
- это виджет, 6 из которых добавляют товар из другой категории, вызывая одно и то же
addProduct
функция, но добавление другого продукта.
Expanded(
child: ElevatedButton(
onPressed: () {
controller.addProduct(
ProductModel(
productName: 'boneless chicken',
category: CategoryModel(categoryName: 'Chicken'),
),
);
},
child: Text('Add chicken'),
),
),
И, наконец, пара небольших изменений в вашем
onInit
. Не забудьте добавить
with SingleGetTickerProviderMixin
в ваш класс GetX, что позволяет вам работать с анимацией и контроллерами вкладок в виджетах без сохранения состояния.
@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
}
А вот и небольшая демонстрация. Графический интерфейс не очень привлекателен, но идею вы поняли.