#flutter
#flutter
Вопрос:
У меня есть следующий экран FiltersScreen, который содержит 2 фильтра и кнопку сохранения. Когда пользователь переключает фильтр и нажимает кнопку сохранения, я хотел бы передать эти значения на экран CategoryMealsScreen. Как я могу передать эти значения? Между этими двумя экранами нет навигации, поэтому я не могу использовать push или pushNamed route.
Вот два класса:
class FiltersScreen extends StatefulWidget {
@override
_FilterScreenState createState() => _FilterScreenState();
}
class _FilterScreenState extends State<FiltersScreen> {
var _glutenFree = false;
var _lactoseFree = false;
Widget _buildSwitchListTile(String title, String subTitle, bool currentValue, Function updateValue){
return SwitchListTile(title:Text(title),
value:currentValue,
subtitle: Text(subTitle),
onChanged: updateValue
);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Filter'),
actions:<Widget>[
IconButton(icon:Icon(Icons.save), onPressed: () { },),
],
),
drawer: MainDrawer(),
body: Column(children:<Widget>[
Container(
padding: EdgeInsets.all(20),
child:Text('Adjust your meal selection',
style:Theme.of(context).textTheme.title), ),
Expanded(
child:ListView(
children:<Widget>[
_buildSwitchListTile('Gluten-free',
'Only include gluten free meals',
_glutenFree,
(newValue){setState((){
_glutenFree = newValue;
},);
}),
_buildSwitchListTile('Lactose',
'Only include lactose free meals',
_lactoseFree,
(newValue){setState((){
_lactoseFree = newValue;
},);
})]
)
)
]));
}
}
Вот класс, который должен получать значения:
class CategoryMealsScreen extends StatefulWidget {
final String categoryId;
final String categoryTitle;
CategoryMealsScreen(this.categoryId, this.categoryTitle);
@override
_CategoryMealsScreenState createState() => _CategoryMealsScreenState();
}
class _CategoryMealsScreenState extends State<CategoryMealsScreen> {
@override
Widget build(BuildContext context) {
final categoryMeals = DUMMY_MEALS.where((meal) {
return meal.categories.contains(widget.categoryId);
}).toList();
return Scaffold(
appBar: AppBar(title: Text(widget.categoryTitle)),
body: ListView.builder(
itemBuilder: (ctx, index) {
return MealItem(
id:categoryMeals[index].id,
title: categoryMeals[index].title,
imageUrl: categoryMeals[index].imageUrl,
duration: categoryMeals[index].duration,
affordability: categoryMeals[index].affordability,
complexity: categoryMeals[index].complexity,
);
},
itemCount: categoryMeals.length,
),
);
}
}
ОТРЕДАКТИРОВАНО
В CategoryMealsScreen
, как я могу использовать оба _glutenFree
и _lactoseFree
значения?
Вот мой обновленный код:
Экран CategoryMealsScreen
class CategoryMealsScreen extends StatefulWidget {
final String categoryId;
final String categoryTitle;
CategoryMealsScreen(this.categoryId, this.categoryTitle);
@override
_CategoryMealsScreenState createState() => _CategoryMealsScreenState();
}
class _CategoryMealsScreenState extends State<CategoryMealsScreen> {
@override
Widget build(BuildContext context) {
ValueListenable<bool> _glutenFree;
ValueListenable<bool> _lactoseFree;
return ValueListenableBuilder(
valueListenable: _glutenFree,
builder: (context, value, _) {
final categoryMeals = DUMMY_MEALS.where((meal) {
if (_glutenFree.value amp;amp; !meal.isGlutenFree) {
return false;
}
if (_lactoseFree.value amp;amp; !meal.isLactoseFree) {
return false;
}
return true;
}).toList();
//Every independent screen must have a scaffold
return Scaffold(
appBar: AppBar(title: Text(widget.categoryTitle)),
body: ListView.builder(
itemBuilder: (ctx, index) {
return MealItem(
id: categoryMeals[index].id,
title: categoryMeals[index].title,
imageUrl: categoryMeals[index].imageUrl,
duration: categoryMeals[index].duration,
affordability: categoryMeals[index].affordability,
complexity: categoryMeals[index].complexity,
);
},
itemCount: categoryMeals.length,
),
);
});
}
}
FiltersScreen
class FiltersScreen extends StatefulWidget {
@override
_FilterScreenState createState() => _FilterScreenState();
}
class _FilterScreenState extends State<FiltersScreen> {
ValueNotifier<bool> _glutenFree = new ValueNotifier(false);
ValueNotifier<bool> _lactoseFree = new ValueNotifier(false);
Widget _buildSwitchListTile(String title, String subTitle, ValueNotifier<bool> currentValue, Function updateValue){
return SwitchListTile(title:Text(title),
value:currentValue.value,
subtitle: Text(subTitle),
onChanged: updateValue
);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Filter'),
actions:<Widget>[
IconButton(icon:Icon(Icons.save), onPressed: () { },),
],
),
drawer: MainDrawer(),
body: Column(children:<Widget>[
Container(
padding: EdgeInsets.all(20),
child:Text('Adjust your meal selection',
style:Theme.of(context).textTheme.title), ),
Expanded(
child:ListView(
children:<Widget>[
_buildSwitchListTile('Gluten-free',
'Only include gluten free meals',
_glutenFree,
(newValue){setState((){
_glutenFree.value = newValue; //setting the value
_glutenFree.notifyListeners(); //all the widget who is listening to this value, let them know the change
},);
}),
_buildSwitchListTile('Lactose',
'Only include lactose free meals',
_lactoseFree,
(newValue){setState((){
_lactoseFree = newValue;
_lactoseFree.notifyListeners();
},);
}),
]
)
)
]));
}
}
Комментарии:
1. Есть ли какой-либо экран, с которого вызываются оба этих класса?
2. Нет, такого экрана нет.
Ответ №1:
Вы можете добиться такого эффекта фильтрации, используя ValueNotifier для хранения изменений класса фильтра и используя ValueListenableBuilder
в классе Category, чтобы прослушать изменение этого значения и внести необходимые изменения в пользовательский интерфейс.
давайте перейдем к решению внутри вашего FiltersScreen
, заменим этот код
var _glutenFree = false;
var _lactoseFree = false;
с ValueNotifier
типом объекта. Итак, это будет выглядеть так
ValueNotifier<bool> _glutenFree = new ValueNotifier(false);
ValueNotifier<bool> _lactoseFree = new ValueNotifier(false);
Изменение значения по щелчку также довольно похоже. Итак, это
setState((){
_glutenFree = newValue;
});
изменится на это
setState((){
_glutenFree.value = newValue; //setting the value
_glutenFree.notifyListeners(); //all the widget who is listening to this value, let them know the change
});
Теперь последний шаг, настройка конструктора виджетов, который прослушивает это изменение значения и перестраивает все его виджеты в дереве.
Для этого просто добавьте это в качестве виджета в свой CategoryMealsScreen
ValueListenableBuilder(
valueListenable: _glutenFree,
builder: (context, value, _) {
});
Комментарии:
1. Спасибо за ответ. Можете ли вы взглянуть на мой отредактированный вопрос и сообщить мне , как я могу использовать оба значения _glutenFree и _lactoseFree на экране CategoryMealsScreen ? Очень ценю вашу помощь