从外部状态范围强制 navDrawer 状态更新

时间:2021-05-05 18:52:53

标签: flutter dart mobile

我目前正在开发电子商务移动应用。

现在我正在处理我的导航。有一堆类别可以有子类别,而子类别可以有自己的子类别。我通过 app init 上的 API 检索所有类别的列表,然后将其存储。

这是我的数据集示例:

{
      "id":"41490",
      "name":"Electrical Equipment",
      "subCategories":[
         {
            "id":"41492",
            "name":"Breakers",
            "subCategories":[
               {
                  "id":"167542",
                  "name":"1 Pole",
                  "subCategories":[
                     {
                        "id":"167577",
                        "name":"15 Amp",
                        "subCategories":null
                     },
                     {
                        "id":"167585",
                        "name":"20 Amp",
                        "subCategories":null
                     },
                     {
                        "id":"167600",
                        "name":"30 Amp",
                        "subCategories":null
                     },
                     {
                        "id":"167606",
                        "name":"40 Amp",
                        "subCategories":null
                     }
                  ]
               },

我正在使用列表视图和列表视图构建器来制作我的类别列表。 列表视图构建器还调用递归函数来创建子类别。 我设法让所有内容都动态生成,这意味着如果我们在网站上添加一堆类别,那么应用程序将通过 API 自动更新。

我现在的问题是,当我单击类别时,navDrawer 不会重绘。我必须关闭类别并重新打开它们以使其重绘。我需要一些新概念,在这个概念上摸索了一段时间。

我认为我的代码结构可能有问题,因为我在状态之外初始化了类别。

这是我的 navDrawer 类:

class navDrawer extends StatefulWidget {
  bool _expandCategories = false;
  bool _expandAccount = false;
  List _categories;
  var _categoryList;
  List _tempSubCats;

  void flickCategories(){
    //_expandCategories = !_expandCategories;
    //sleep(const Duration(microseconds: 100));
    //_expandCategories = !_expandCategories;
  }

  void setCategories(List categories){
      _categories = categories;
      int catCount = categories.length;
      _categoryList = new ListView.builder(
          //shrinkWrap: true,
          //physics: ClampingScrollPhysics(),
          padding:EdgeInsets.all(0.0),
          itemCount: catCount,
          itemBuilder: (BuildContext context, int index) => buildCategories(context, index),
      );
  }
  Widget buildCategories(BuildContext context, int index){
    if(_categories[index]['subCategories']!=null){
      if(idHandler.isIdOpen(_categories[index]['id'])){
        _tempSubCats = [];
        buildSubCategories(_categories[index],2);
        ListView subCategories = new ListView.builder(
            shrinkWrap: true,
            physics: NeverScrollableScrollPhysics(),
            itemCount: _tempSubCats.length,
            itemBuilder: (BuildContext ct, int i){
                return _tempSubCats[i];
            }
        );
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
              height: 30.0,
              child: ListTile(
                  title: Row(
                      children: [
                        Text("    " + _categories[index]['name']),
                        Transform.rotate(
                            angle: -math.pi/2,
                            child:
                            Transform.scale(
                                scale: 0.75,
                                child:
                                Icon(Icons.arrow_back)
                            )
                        )
                      ]
                  ),
                  onTap: () {
                    flickCategories();
                    idHandler.toggleId(_categories[index]['id']);
                  }
              ),
              padding: EdgeInsets.all(0.0),
              margin: EdgeInsets.all(0.0)
          ),
          MediaQuery.removePadding(
              removeTop: true,
              removeBottom: true,
              removeLeft: true,
              removeRight: true,
              context: context,
              child: subCategories
          )
          ]
        );
      } else {
        return Container(
            height: 30.0,
            child: ListTile(
                title: Row(
                    children: [
                      Text("    " + _categories[index]['name']),
                      Transform.scale(
                          scale: 0.75,
                          child:
                          Icon(Icons.arrow_back)
                      )
                    ]
                ),
                onTap: () {
                  flickCategories();
                  idHandler.toggleId(_categories[index]['id']);
                }
            ),
            padding: EdgeInsets.all(0.0),
            margin: EdgeInsets.all(0.0)
        );
      }
    } else {
      return Container(
          height: 30.0,
          child: ListTile(
              title: Text("    "+_categories[index]['name']),
              onTap: () {
                  //TODO: implement category navigation
              }
          ),
          padding: EdgeInsets.all(0.0),
          margin: EdgeInsets.all(0.0)
      );
    }
  }

  void buildSubCategories(var parent, int depth){
    if(parent['subCategories']!=null){
      List subCategoryList = parent['subCategories'];
      int subCategoryCount = subCategoryList.length;
      //Column subCats = new Column();
          if(idHandler.isIdOpen(parent['id'])) {
            for (var i = 0; i < subCategoryCount; i++) {
              String formattedCategory = indentCategory(parent['subCategories'][i]['name'], depth);
              _tempSubCats.add(
                parent['subCategories'][i]['subCategories']!=null ?
                    Container(
                        height:20.0,
                        child:
                          ListTile(
                            title: idHandler.isIdOpen(parent['subCategories'][i]['id']) ?
                              Row(
                                children:[
                                    Text(formattedCategory),
                                    Transform.rotate(
                                      angle:-math.pi/2,
                                      child:
                                        Transform.scale(
                                          scale:0.75,
                                          child:
                                            Icon(Icons.arrow_back)
                                        )
                                    )
                                ]
                              )
                              :
                              Row(
                                children: [
                                    Text(formattedCategory),
                                    Transform.scale(
                                      scale: 0.75,
                                      child:
                                        Icon(Icons.arrow_back)
                                    )
                                ]
                              ),
                            onTap: (){
                              flickCategories();
                              idHandler.toggleId(parent['subCategories'][i]['id']);
                            }
                          )
                    )
                    :
                    Container(
                      height:20.0,
                      child:
                        ListTile(
                          title: Text(formattedCategory),
                          onTap: (){
                            //TODO: implement category navigation
                          }
                        )
                    )
              );
              buildSubCategories(parent['subCategories'][i], depth+1);
            }
          }
      }
  }

  String indentCategory(String input, int amount){
    String output='';
      for(var i=0; i<amount; i++){
          output += '    ';
      }
      output+=input;
      return output;
  }

  @override
  _navDrawerState createState() => _navDrawerState();
}
class _navDrawerState extends State<navDrawer>{
  @override
  Widget build(BuildContext Context){
      return Drawer(
          child:
          Container(
            padding:EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 5),
            child:
              Column(
                children:[
                      Container(
                          height:80.0,
                          width:double.infinity,
                          child:
                          DrawerHeader(
                              child: Text('Menu'),
                              decoration: BoxDecoration(
                                  gradient: LinearGradient(
                                      begin: Alignment.topLeft,
                                      end: Alignment.bottomRight,
                                      colors: <Color>[
                                        Colors.grey,
                                        Colors.red
                                      ])
                              )
                          ),
                          margin:EdgeInsets.all(0.0),
                          padding:EdgeInsets.all(0.0)
                      ),
                      Expanded(
                        child:
                          ListView(
                              padding:EdgeInsets.zero,
                              children: <Widget>[
                                widget._expandCategories?
                                Column(
                                  children:[
                                    Container(
                                      height:40.0,
                                      child: ListTile(
                                        title: Row(
                                          children: [
                                            Text('Categories'),
                                            Transform.rotate(
                                              angle: -math.pi/2,
                                              child:
                                                Transform.scale(
                                                  scale: 0.75,
                                                  child:
                                                    Icon(Icons.arrow_back)
                                              )
                                            )
                                          ]
                                        ),
                                        onTap:() {
                                          _expandCat();
                                        }
                                      )
                                    ),
                                    MediaQuery.removePadding(
                                      removeTop:true,
                                      context: context,
                                      child:
                                        SizedBox(
                                          height:300.0,
                                          child: widget._categoryList,
                                          
                                        )
                                    )
                                  ]
                                )
                                :Container(
                                    height:40.0,
                                    child:
                                    ListTile(
                                        title: Row(
                                            children: [
                                              Text('Categories'),
                                              Transform.scale(
                                                  scale: 0.75,
                                                  child:
                                                  Icon(Icons.arrow_back)
                                              )
                                            ]
                                        ),
                                        onTap:(){
                                          _expandCat();
                                          //Update state of the app
                                        }
                                    ),
                                    margin:EdgeInsets.all(0.0),
                                    padding:EdgeInsets.all(0.0)
                                ),
                                Container(
                                    height:40.0,
                                    child:
                                    ListTile(
                                        title:Text('Your quotes'),
                                        onTap:(){
                                          //Update state of the app
                                        }
                                    ),
                                    margin:EdgeInsets.all(0.0),
                                    padding:EdgeInsets.all(0.0)
                                ),
                                widget._expandAccount?
                                Column(
                                  children:[
                                    Container(
                                        height:40.0,
                                        child:
                                        ListTile(
                                            title: Row(
                                                children:[
                                                  Text('Your account'),
                                                  Transform.rotate(
                                                    angle:-math.pi/2,
                                                    child:
                                                    Transform.scale(
                                                        scale:0.75,
                                                        child:
                                                        Icon(Icons.arrow_back)
                                                    )
                                                  )
                                                ]
                                            ),
                                            onTap:(){
                                              _expandAcc();
                                            }
                                        ),
                                        margin:EdgeInsets.all(0.0),
                                        padding:EdgeInsets.all(0.0)
                                    ),
                                    Container(
                                      height:30.0,
                                      child:
                                        ListTile(
                                          title:Text('        Your Information'),
                                          onTap:(){

                                          }
                                        )
                                    ),
                                    Container(
                                        height:30.0,
                                        child:
                                        ListTile(
                                            title:Text('        Your Address'),
                                            onTap:(){

                                            }
                                        )
                                    ),
                                    Container(
                                        height:30.0,
                                        child:
                                        ListTile(
                                            title:Text('        Listed Equipment'),
                                            onTap:(){

                                            }
                                        )
                                    ),
                                    Container(
                                        height:30.0,
                                        child:
                                        ListTile(
                                            title:Text('        Add Equipment'),
                                            onTap:(){

                                            }
                                        )
                                    ),
                                  ]
                                )
                                :Container(
                                    height:40.0,
                                    child:
                                    ListTile(
                                        title: Row(
                                            children:[
                                              Text('Your account'),
                                              Transform.scale(
                                                  scale:0.75,
                                                  child:
                                                  Icon(Icons.arrow_back)
                                              )
                                            ]
                                        ),
                                        onTap:(){
                                          _expandAcc();
                                        }
                                    ),
                                    margin:EdgeInsets.all(0.0),
                                    padding:EdgeInsets.all(0.0)
                                )
                              ]
                          ),
                      )
                  ]
              )
          )
      );
  }
  void _expandCat(){
      setState((){
        widget._expandCategories=!widget._expandCategories;
      });
  }
  void _expandAcc(){
      setState((){
        widget._expandAccount=!widget._expandAccount;
      });
  }
}

注意:idHandler 是 main.dart 的公共成员。
注2:flickCategories() 是我更新状态的尝试之一。

在下面的截图中你可以明白我的意思:
Categories open

如果我单击“电气设备”,则必须单击“类别”两次才能使其重绘,并且必须滚动回列表中的位置。

那么,当我的某个类别被点击时,我该如何更新状态?
我需要像有状态类别小部件之类的东西吗?
我正在尝试使用箭头和缩进等使其看起来响应。

1 个答案:

答案 0 :(得分:0)

这是我自己想出来的。

我需要制作一个 productCategory 有状态小部件并从小部件内部更新其状态。

每个 productCategory 小部件都有一个代表子类别的列表。在我的递归过程中,我添加到每个 productCategory 的 subCategories。

productCategory 小部件正确重绘自身,因为我调用了 setState(),它具有将滚动位置保持在原来位置的额外好处。

这是我的 productCategory 小部件:

class productCategory extends StatefulWidget{
  String _id = '';
  String _name = '';
  List<productCategory> _subCategories = [];

  productCategory(String id, String name){
    _id = id;
    _name = name;
  }

  void addAllSubCategories(List<productCategory> subCats){
    _subCategories.addAll(subCats);
  }

  void addSubCategory(productCategory cat){
    _subCategories.add(cat);
  }

  void setName(String name){
    _name = name;
  }

  void setId(String id){
    _id = id;
  }

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

}
class _productCategoryState extends State<productCategory>{
  @override
  Widget build(BuildContext context) {
    if(widget._subCategories.isNotEmpty){
      if(idHandler.isIdOpen(widget._id)){
        return Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Container(
                  height: 30.0,
                  child: ListTile(
                      title: Row(
                          children: [
                            Text(widget._name),
                            Transform.rotate(
                                angle: -math.pi/2,
                                child:
                                Transform.scale(
                                    scale: 0.75,
                                    child:
                                    Icon(Icons.arrow_back)
                                )
                            )
                          ]
                      ),
                      onTap: () {
                        setState((){
                          idHandler.toggleId(widget._id);
                        });
                      }
                  ),
                  padding: EdgeInsets.all(0.0),
                  margin: EdgeInsets.all(0.0)
              ),
              MediaQuery.removePadding(
                  removeTop: true,
                  removeBottom: true,
                  removeLeft: true,
                  removeRight: true,
                  context: context,
                  child: ListView.builder(
                    physics: NeverScrollableScrollPhysics(),
                    shrinkWrap: true,
                    padding: EdgeInsets.all(0.0),
                    itemCount: widget._subCategories.length,
                    itemBuilder: (BuildContext context, int index){
                      return widget._subCategories[index];
                    }
                  )
              )
            ]
        );
      } else {
        return Container(
            height: 30.0,
            child: ListTile(
                title: Row(
                    children: [
                      Text(widget._name),
                      Transform.scale(
                          scale: 0.75,
                          child:
                          Icon(Icons.arrow_back)
                      )
                    ]
                ),
                onTap: () {
                  setState((){
                    idHandler.toggleId(widget._id);
                  });
                }
            ),
            padding: EdgeInsets.all(0.0),
            margin: EdgeInsets.all(0.0)
        );
      }
    } else {
      return Container(
          height: 30.0,
          child: ListTile(
              title: Text(widget._name),
              onTap: () {
                //TODO: implement category navigation
              }
          ),
          padding: EdgeInsets.all(0.0),
          margin: EdgeInsets.all(0.0)
      );
    }
  }
}