如何根据另一个小部件的点击方法刷新小部件

Posted

技术标签:

【中文标题】如何根据另一个小部件的点击方法刷新小部件【英文标题】:How to refresh a widget based on another widget's on tap method 【发布时间】:2021-06-09 10:47:33 【问题描述】:

在我的 Flutter UI 中,我想在用户选择特定类别时刷新项目列表。我还想让选择的类别成为活动类别。这是我的用户界面的样子:

这是显示类别的代码:

@override
  Widget build(BuildContext context) 
     var categoriesData =   Provider.of<Categories>(context);
    return SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: categoriesData.items
          .map(
            (catData) => CategoryItemNew(
                  id:catData.id,
                  title:catData.title,
                  isActive:categoriesData.items.indexOf(catData)==0?true:false
                ),
          )
          .toList(),
      ),
    );
  

这是每个类别项目的代码:

class CategoryItemNew extends StatefulWidget 
  final String title;
  final String id;
  bool isActive;
  final Function press;
  CategoryItemNew(
    @required this.id,
    @required this.title,
    this.isActive
  );

  @override
  _CategoryItemNewState createState() => _CategoryItemNewState();


class _CategoryItemNewState extends State<CategoryItemNew> 
  @override
  Widget build(BuildContext context) 
    return GestureDetector(
      onTap: () => selectCategory(context),
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
        child: Column(
          children: <Widget>[
            Text(
              widget.title,
              style: widget.isActive
                  ? TextStyle(
                      color: kTextColor,
                      fontWeight: FontWeight.bold,
                    )
                  : TextStyle(fontSize: 12),
            ),
            if (widget.isActive)
              Container(
                margin: EdgeInsets.symmetric(vertical: 5),
                height: 3,
                width: 22,
                decoration: BoxDecoration(
                  color: kPrimaryColor,
                  borderRadius: BorderRadius.circular(10),
                ),
              ),
          ],
        ),
      ),
    );
  

  void selectCategory(BuildContext ctx) 
   // What should I do here? 
  

这是显示产品的代码:

class ItemList extends StatefulWidget 
  static const routeName = '/item-list';
  String title = ''; 
  ItemList(this.title);  

  @override
  _ItemListState createState() => _ItemListState();


class _ItemListState extends State<ItemList> 
  var _isInit = true;
  var _isLoading = false;
 

   void didChangeDependencies() 
    if (_isInit) 
      setState(() 
        _isLoading = true;
      );
       Provider.of<Products>(context).fetchAndSetProducts(widget.title, true).then((_) 
        setState(() 
          _isLoading = false;
        );
      );
    
    _isInit = false;
    super.didChangeDependencies();
  

  @override
  Widget build(BuildContext context) 
     final productsData =   Provider.of<Products>(context); 
    return _isLoading? CircularProgressIndicator():SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: Row(
         children:productsData.items
          .map(
            (productData) => ItemCard(
                  svgSrc: "assets/icons/burger_beer.svg",
                  //id:catData.id,
                  title: productData.title
                  //title:productData.title,
                ),
          )
          .toList(),
      ),
    );
  

当应用程序启动时,我可以获取类别并且还可以显示“汉堡包和包装”类别的项目。但是,我不知道当用户选择另一个类别时如何刷新项目列表以及如何使该类别成为活动类别。

在 Mickael 回复后更新 CategoryItem 类

 String previousId =''; 
// ignore: must_be_immutable
class CategoryItemNew extends StatefulWidget 
  final String title;
  final String id;
  bool isActive;
  final Function press;
  CategoryItemNew(
    @required this.id,
    @required this.title,
    this.isActive,
  );
  @override
  _CategoryItemNewState createState() => _CategoryItemNewState();



class _CategoryItemNewState extends State<CategoryItemNew> 

  String id; 
  ValueNotifier valueNotifier;
   
  void initState() 
    id = widget.id;
   valueNotifier = ValueNotifier(previousId);
   print('ID in initstate is ' + id); 
    super.initState();
  

  isIdUpdated(String id) 
     print('previous in updateid is ' + previousId);
    if(previousId != id)
     
      previousId = id; 
     valueNotifier.value = id;
     print('ID in updateid is ' + id); 
    
  
  @override
  Widget build(BuildContext context) 
    return GestureDetector(
      onTap: () => selectCategory(context),
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
        child: Column(
          children: <Widget>[
            Text(
              widget.title,
              style: widget.isActive
                  ? TextStyle(
                      color: kTextColor,
                      fontWeight: FontWeight.bold,
                    )
                  : TextStyle(fontSize: 12),
            ),
            if (widget.isActive)
              Container(
                margin: EdgeInsets.symmetric(vertical: 5),
                height: 3,
                width: 22,
                decoration: BoxDecoration(
                  color: kPrimaryColor,
                  borderRadius: BorderRadius.circular(10),
                ),
              ),
          ],
        ),
      ),
    );
  

  ValueListenableBuilder selectCategory(BuildContext ctx) 
     isIdUpdated(id); 
   return ValueListenableBuilder(
      valueListenable: valueNotifier,
      builder: (context, value, child) 
        print('inside listenabele builder'); 
        return ItemList(widget.title);
      ,
    );
  

   

请注意,我在 ValueListenableBuilder 的构建器中有一个打印语句。这个打印语句永远不会被执行。我做错了什么?

【问题讨论】:

【参考方案1】:

您必须添加一个 ValueListener 来侦听您要显示的类别的值。当您单击一个类别时,您必须将新值添加到您的 ValueListener。

一旦完成,创建一个ValueListenableBuilder,它会在每次其值更改时构建。在构建器中,您可以根据您正在收听的值显示您想要的小部件。

编辑:“活动”类别的内容相同,您可以使用相同的值。

【讨论】:

你能根据我分享的代码提供一个例子吗? 我这样做了,但它不会触发 itemlist 类。我究竟做错了什么? ValueListenableBuilder selectCategory(BuildContext ctx) print('Inside value listenable'); ValueNotifier valueNotifier = ValueNotifier(widget.id); return ValueListenableBuilder( valueListenable: valueNotifier, builder: (context, value, child) return ItemList(widget.title); , ); valueNotifier = ValueNotifier(widget.id);仅用于初始化。当您单击类别时,像这样更新您的值: valueNotifier.add(clickValue); .之后,在 ValueListenableBuilder 的构建器中,您可以将所需的内容返回给您的 ValueNotifier 值,如下所示: builder:(context,value,child) if(value == 1) return BugerList() else if 返回 TacosList() 否则 ... 我的代码中的点击值是多少?我假设类别 ID? 它可以是任何你想要的。但就您而言,是的,类别 ID 似乎是个好主意。要更新您的 ValueNotifier,只需尝试添加一个 GestureDetector 来捕获您的类别 onClick 的值。类似于: GestureDetector(onTap: () valueNotifier.add(category.id)

以上是关于如何根据另一个小部件的点击方法刷新小部件的主要内容,如果未能解决你的问题,请参考以下文章

让小部件在点击另一个小部件时显示 Flutter

如何实现可点击的文本小部件 Flutter?

如何根据 Flutter 中的按钮单击向上和向下移动一个小部件?

如何在通知中心频繁更新今日小部件?

是刷新小部件的方法,它是颤动的关键

如何每秒刷新小部件?