【问题标题】:Passing data between two unrelated screens in flutter在颤动的两个不相关的屏幕之间传递数据
【发布时间】:2021-01-03 15:39:14
【问题描述】:

我有以下 FiltersScreen,其中包含 2 个过滤器和一个保存按钮。当用户切换过滤器并单击保存按钮时,我想将这些值传递给 CategoryMealsScreen。我怎样才能传递这些值?这两个屏幕之间没有导航,所以我不能使用 push 或 pushNamed 路由。

这是两个类:

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 && !meal.isGlutenFree) {
                  return false;
                }
                if (_lactoseFree.value && !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(); 
                   },); 
                  }),
                  ]
              )
            )
        ]));
  }
}

【问题讨论】:

  • 是否有任何屏幕可以调用这两个类?
  • 不,没有这样的屏幕。

标签: flutter


【解决方案1】:

您可以通过使用ValueNotifier 来保存过滤器类的更改并在Category 类中使​​用ValueListenableBuilder 来监听该值的更改并在UI 中进行必要的更改来实现这种过滤器效果。

让我们跳到解决方案,在您的 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, _) {
});

【讨论】:

  • 感谢您的回答。你能看看我编辑的问题,让我知道如何在 CategoryMealsScreen 中同时使用 _glutenFree 和 _lactoseFree 值吗?非常感谢您的帮助
猜你喜欢
  • 2020-02-20
  • 1970-01-01
  • 2020-02-12
  • 2019-11-01
  • 1970-01-01
  • 2021-03-01
  • 2018-12-27
  • 2017-11-08
  • 2019-05-20
相关资源
最近更新 更多