Как обновить виджет с сохранением состояния в окне навигации, сохраняя тот же класс, что и фрагменты в Android? - PullRequest
0 голосов
/ 07 июня 2018

Я хочу обновить виджет с сохранением состояния моего класса, возвращая тот же класс после получения данных с сервера, из ящика навигации.У меня проблема с тем, что класс загружает данные только один раз и остается прежним, если я перехожу к другому элементу моего навигационного ящика.Потому что государство создается только один раз.

Вот мой код:

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";
}
 }

Вот как я вызываю этот класс 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 голосов
/ 07 июня 2018

Я бы предложил вместо вызова метода для загрузки данных в методе initState вашего класса использовать виджет FutureBuilder.Если вы возвращаете новый 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, вы можете сделать рефакторинг, чтобы сделать что-то лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...