如何更新导航抽屉中的有状态小部件,同时在Android中保持像片段一样的类?

时间:2018-06-07 15:22:38

标签: flutter

我希望在从服务器获取数据后从导航抽屉返回同一类时更新我的​​类的有状态窗口小部件。我遇到的问题是,如果我导航到导航抽屉的另一个项目,那么类只加载一次数据并保持不变。因为状态只创建一次。

这是我的代码:

class CategoryFilter extends StatefulWidget {
 int productIndex;
 String category_name;
 CategoryFilter(this.productIndex, this.category_name)
 {
  print("CategoryFilter");
  print(productIndex);
  print(category_name);
  new _CategoryFilterState(productIndex, category_name);
}

 @override
 _CategoryFilterState createState() => new 
_CategoryFilterState(productIndex, category_name);
}

 class _CategoryFilterState extends State<CategoryFilter> {

 int productIndex;
 List<ResponseDataProducts> productList;
 List data;
 String category_name;

_CategoryFilterState(this.productIndex, this.category_name)
 {
   print("CategoryFilter");
   print(productIndex);
  print(category_name);
}

@override
void initState(){
super.initState();

    Future<String> status = getData(productIndex);

    status.then((onValue){

    if(onValue.toString() == "Success")
    {

      Navigator.pop(context);

    }

  });


  // this.getData();
 }

 @override
 Widget build(BuildContext context) {
  return new Scaffold(

    body: new Container(
        color: Colors.white30,

        child: new ListView.builder(
           itemCount: productList == null ? 0 : productList.length,
           itemBuilder: (BuildContext context, int index) {

             return new Container(

               margin: const EdgeInsets.only( bottom: 10.0),
               constraints: new BoxConstraints.expand(
                  height: 200.0

               ),
               alignment: Alignment.bottomLeft,

               decoration: new BoxDecoration(
                   image: new DecorationImage(image:
                   new NetworkImage
                     ("http://myurl.com/"+productList[index].thumbnail),
                      fit: BoxFit.cover)
               ),
               child:new Container(

                 child: new Text(
                   productList[index].name,
                   style: new TextStyle(color: Colors.white, fontSize: 30.0),
                 ),
                color: Colors.black54,
                 alignment: new FractionalOffset(0.5, 0.0),
                 height: 35.0,
                 // margin: const EdgeInsets.symmetric(vertical: 30.0),

               ),
             );
            })
    ),
  ) ;
}



  void _onLoading()
  {
    showDialog(context: context,
       barrierDismissible: false,
      child: progress);

    new Future.delayed(new Duration(seconds: 2), (){
    // Navigator.pop(context);
   });

  }


   Future<String> getData(int productIndex) async {
   productList = new List<ResponseDataProducts>();


     _onLoading();

   http.Response response = await http.get(
       Uri.encodeFull(CommonMethods.base_url + 'product/$productIndex'),
    headers: {"Accept": "application/json"});

print(response.body);

  setState(() {
    var convertDataToJson = JSON.decode(response.body);
    data = convertDataToJson["responseData"];
    for(int i=0; i<data.length; i++)
  {

    ResponseDataProducts responseData = new ResponseDataProducts(
        data[i]["id"],
        data[i]["name"], data[i]["description"],
        data[i]["title"], data[i]["thumbnail"]);
    productList.add(responseData);
  }
  //Navigator.pop(context);

});

return "Success";
}
 }

以下是我如何从Navigation Drawer调用此categoryFilter类:

_getDraserItemWidget(int pos)
 {
  switch(pos)
  {
  case 0:

    return new Home(bar_id);


  case 1:



    return  new CategoryFilter(categoryList[pos-1].id, categoryList[pos-1].name);



  case 2:



  return  new CategoryFilter(categoryList[pos-1].id, categoryList[pos-1].name);


  case 3:


    return  new CategoryFilter(categoryList[pos-1].id, categoryList[pos-1].name);


  case 4:

    return new OpeningTime();


  case 5:

    break;



 }
 }

1 个答案:

答案 0 :(得分:0)

我建议您使用FutureBuilder窗口小部件,而不是调用方法在类的initState方法中加载数据。如果您从导航抽屉中返回一个新的FutureBuilder,那么每次创建新的时都会调用您的服务,并且通常是执行异步请求的更好方式。

这是一个非常简单的例子。它不能很好地完成抽屉(或者其他一些东西 - 只有这么多时间花在这样的事情上),但它应该说明这个概念。

请注意,它不是“更新小部件”,而只是创建一个新的小部件。由于颤动的方式,这应该是相对高效的,特别是因为你不是一直这样做,而是只有当用户从导航菜单中选择一些东西时。

import 'dart:async';

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new MyAppState();
}

class MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new TextPage(text: "Home!"),
    );
  }
}

Map<int, int> _nums = Map();

class TextPage extends StatelessWidget {
  final String text;

  const TextPage({Key key, @required this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new PreferredSize(
        child: new Container(),
        preferredSize: Size.fromHeight(10.0),
      ),
      body: new Center(
        child: new Text(text),
      ),
      drawer: new Builder(
        builder: (context) => Material(
              child: new SafeArea(
                child: Column(
                  children: <Widget>[
                    new FlatButton(
                      onPressed: () {
                        Navigator.pushReplacement(
                            context, new MaterialPageRoute(builder: (context) => _getDrawerItemWidget(1)));
                      },
                      child: Text("First item"),
                    ),
                    new FlatButton(
                      onPressed: () {
                        Navigator.pushReplacement(
                            context, new MaterialPageRoute(builder: (context) => _getDrawerItemWidget(2)));
                      },
                      child: Text("Second item"),
                    ),
                  ],
                ),
              ),
            ),
      ),
    );
  }

  _getDrawerItemWidget(int i) {
    return new FutureBuilder<String>(
      builder: (context, AsyncSnapshot<String> snapshot) {
        if (snapshot.data != null) {
          return new TextPage(text: snapshot.data);
        } else {
          return new TextPage(text: "Loading.");
        }
      },
      future: () async {
        var num = _nums.putIfAbsent(i, () => 0);
        _nums[i] = num + 1;
        String toReturn = "You retrieved number $i for the $num time";
        return await Future.delayed<String>(Duration(seconds: 1), () => toReturn);
      }(),
    );
  }
}

理论上你可以做一些不同的事情,保持GlobalKey引用,并使用它们调用子窗口小部件上的方法,如果它与当前选择匹配,让它更新,但这通常是一个不好的主意 - 最好的做法鼓励你通过小部件树中的数据向下,而不是向下调用函数。如果你必须使用GlobalKeys,你通常可以重构做更好的事情。