Как обновить ListView при удалении из него виджета? - PullRequest
0 голосов
/ 12 апреля 2020

Я начинающий разработчик во Flutter, и я пытаюсь создать список пользовательских виджетов Card PositionWidget внутри Favorite виджета. Информация для самой карты это получить и API. Я добавил кнопку удаления в каждый PositionWidget списка, чтобы удалить этот виджет из списка, но я не знаю, как обновить sh список при нажатии кнопки удаления и удалении элемента из List<String> favorites. Кто-нибудь знает, как это сделать или может связать некоторые ресурсы, чтобы узнать это? Спасибо!

class Favourites extends StatefulWidget {
  @override
  _FavouritesState createState() => _FavouritesState();
}

class _FavouritesState extends State<Favourites> {

  List<String> favourites = List<String>();
  final dio = new Dio();

  Future<List<String>> getData() async {
    favourites=MySharedPreferences().favoritePositions;
    List<String> dates = List<String>();
    for (var i=0; i < favourites.length; i++) {
      Response response = await dio.get('http://...api');
      dates.add(response.data['data']);
    }
    return dates;
  }
  Widget getFavourites() {
    return FutureBuilder(
        future: getData(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            if (snapshot.data.length > 0) {
              return ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, index) {
                    return Container(
                      padding: EdgeInsets.fromLTRB(10, 10, 10, 5),
                      height: 140,
                      width: double.maxFinite,
                        child: PositionWidget(key: new Key(index.toString()), streetName: favourites[index], date: snapshot.data[index])
                    );
                  }
              );
            } 
          }
        }
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: getFavourites(),
    );
  }
}

class PositionWidget extends StatefulWidget {
   final String streetName;
   String date;
   PositionWidget({Key key, this.streetName, this.date}) : super(key: key); 

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

  ....
}


1 Ответ

1 голос
/ 12 апреля 2020

Итак, у вас есть StatefulWidget - давайте воспользуемся этим. Я не могу проверить часть своего кода, так как у меня нет рабочего образца, и я вдали от своего рабочего места. Но суть будет:

  1. Создать локальную переменную, в которой будет храниться результат вызова API
  2. . Используйте SetState, чтобы обновить его, чтобы пользовательский интерфейс знал, что он обновлен
  3. Измените ListView таким образом, чтобы он использовал эту новую переменную (_dates)
  4. Установите проверку тела, если переменная установлена, в то время как не установлено, показывает индикатор загрузки
  5. Создайте voidcallback на PositionWidget, который может использоваться в родительском виджете
  6. Пусть родительский виджет вызовет функцию void, которая удаляет, удаляет элемент по индексу, указанному при настройке состояния, чтобы пользовательский интерфейс знал.

Я действительно надеюсь, что это код верен, если нет, дайте мне знать, и я могу попытаться помочь :) - прошло много времени с тех пор, как я использовал setState для взаимодействия с API, поэтому я мог сделать что-то не так - обычно я использую BLO C для управления состояниями, поэтому, пожалуйста, дайте мне знать, если вам нужна дополнительная помощь. Вот пример кода:

class Favourites extends StatefulWidget {
  @override
  _FavouritesState createState() => _FavouritesState();
}

class _FavouritesState extends State<Favourites> {
  List<String> _dates;

  List<String> favourites = List<String>();
  final dio = new Dio();

  Future<List<String>> getData() async {
    favourites=MySharedPreferences().favoritePositions;
    List<String> dates = List<String>();
    for (var i=0; i < favourites.length; i++) {
      Response response = await dio.get('http://...api');
      dates.add(response.data['data']);
    }
    return dates;
  }

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

    getData().then((dates) {
      if(mounted) setState(() => _dates = dates);
    })//You should catch error here too....
  }

  void _deleteItem(int index) {
    if(mounted) setState(() {
      _dates.removeAt(index);
      //I assume you want to remove favorites as well otherwise the two indeces will go out of sync? Maybe?
      //favourites.removeAt(index)
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _dates == null ?
      Center(child: CircularProgressIndicator()) :
      ListView.builder(
        itemCount: _dates.length,
        itemBuilder: (context, index) {
          return Container(
            padding: EdgeInsets.fromLTRB(10, 10, 10, 5),
            height: 140,
            width: double.maxFinite,
              child: PositionWidget(key: new Key(index.toString()), streetName: favourites[index], date: _dates.data[index], onDelete: () => _deleteItem(index))
          );
        },
      );
    );
  }
}

class PositionWidget extends StatefulWidget {
   final String streetName;
   String date;
   final VoidCallBack onDelete;
   PositionWidget({Key key, this.streetName, this.date, @required this.onDelete}) : super(key: key); 

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

  ///Wherever you have a button or gesture detector or whatever you can click/tap you can call widget.onDelete():
  ///For eg, onTap: () => widget.onDelete()
  ....
}
...