Flutter:将列表另存为收藏

聪明的HO

我有一个看起来像这样的JSON数据文件,您可以看到“吸引力”本身就是每个城市下的列表:

[
    {
        "city": "text text text",
        "attractions": [
            "text text ",
            "text text"
        ],
    },
    {
        "city": "text text text",
        "attractions": [
            "text text",
            "text text",
        ],
    },
]

以下代码基本上是一个从上述JSON获取数据的listview构建器。现在,单击城市时,它将导航到下一页,其中显示该城市的景点列表。从代码中可以看到,有一个选项可以将另一页中的城市保存为收藏夹,该选项可以显示在保存的收藏夹的另一个列表中:

class Index extends StatefulWidget {
  @override
  _IndexState createState() => _IndexState();
}
List data;
List<Cities> citylist = List();
List<Cities> citysavedlist = List();
int index;
class _IndexState extends State<Index> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: listView(),
    );
  }
  Future<String> fetchData() async {
    String data =
        await DefaultAssetBundle.of(context).loadString("assets/data.json");
    final jsonResult = json.decode(data);
    this.setState(() {
      jsonResult
          .forEach((element) => citylist.add(new Cities.fromJson(element)));
    });
    return "Success!";
  }

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

  listView() {
    return ListView.builder(
      itemCount: citylist == null ? 0 : citylist.length,
      itemBuilder: (context, index) {
        return Column(
          children: <Widget>[_buildRow(index, citylist)],
        );
      },
    );
  }

  Widget _buildRow(index, citylist) {
    final bool alreadySaved = citysavedlist.contains(citylist[index]);
    return Padding(
      padding: const EdgeInsets.only(top: 5.0, left: 5.0, right: 5.0),
      child: Card(
        child: ListTile(
            title:
                Text(citylist[index].title, style: TextStyle(fontSize: 22.0)),
            trailing: IconButton(
              icon: Icon(
                alreadySaved ? Icons.star : Icons.star_border,
                color: alreadySaved ? Colors.blue : Colors.blue,
              ),
              onPressed: () {
                setState(() {
                  if (alreadySaved) {
                    citysavedlist.remove(citylist[index]);
                  } else {
                    citysavedlist.add(citylist[index]);
                  }
                });
              },
            ), //subtitle: Text(subtitle),
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => Detail(citylist[index])));
            }),
      ),
    );
  }


void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          final Iterable<ListTile> tiles = citysavedlist.map(
            (Cities pair) {
              return ListTile(
                  title: Text(
                    pair.city,
                  ),
                  onTap: () {
                    Navigator.push(context,
                        MaterialPageRoute(builder: (context) => Detail(pair)));
                  });
            },
          );

          final List<Widget> divided = ListTile.divideTiles(
            context: context,
            tiles: tiles,
          ).toList();
          return Scaffold(
            appBar: AppBar(
              title: const Text('Saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }
}

这是模型类:

List<Cities> citiesFromJson(String str) =>
    List<Cities>.from(json.decode(str).map((x) => Cities.fromJson(x)));
String citiesToJson(List<Cities> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Cities {
  Cities({
    this.city,
    this.attractions,
  });

  String city;
  List<String> attractions;

  factory Cities.fromJson(Map<String, dynamic> json) => Cities(
        city: json["city"],
        attractions: List<String>.from(json["attractions"].map((x) => x)),
      );

  Map<String, dynamic> toJson() => {
        "city": city,
        "attractions": List<dynamic>.from(attractions.map((x) => x)),
      };
}

以下代码是我需要您帮助的地方,它用于详细信息页面,当某人单击某个城市时,此页面以列表形式显示每个城市的景点。在此页面中,我希望能够将景点另存为收藏夹,以便在其他页面中显示。

class Detail extends StatefulWidget {
  final Cities cities;
  Detail(this.cities);
  @override
  _DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.cities.city),
      ),
      body: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                widget.cities.city,
                style: TextStyle(fontSize: 20),
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: widget.cities.attractions.length,
                itemBuilder: (BuildContext context, int index) {
                  return Card(
                      child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text(widget.cities.attractions[index]),
                  ));
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

我需要您的帮助,请添加此功能“将景点另存为收藏”。我需要将所有保存的景点显示在一个“保存的景点页面”中,无论它属于哪个城市。

有人可以帮忙吗

萨加尔·阿查里亚

看看我做的例子。以下是我添加的json,我只是将数据更改为您的理解

[
   {
       "city": "Canada",
       "attractions": [
           "Niagara Falls: An Elegant View",
           "Whistler: Your Perfect Ski Resort"
       ]
   },
   {
       "city": "Germany",
       "attractions": [
           "Berlin",
           "Munich"
       ]
   }
]

您提供的json中的模型类:

// To parse this JSON data, do
//
//     final cities = citiesFromJson(jsonString);

import 'dart:convert';

List<Cities> citiesFromJson(String str) => List<Cities>.from(json.decode(str).map((x) => Cities.fromJson(x)));

String citiesToJson(List<Cities> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Cities {
    Cities({
        this.city,
        this.attractions,
    });

    String city;
    List<String> attractions;

    factory Cities.fromJson(Map<String, dynamic> json) => Cities(
        city: json["city"],
        attractions: List<String>.from(json["attractions"].map((x) => x)),
    );

    Map<String, dynamic> toJson() => {
        "city": city,
        "attractions": List<dynamic>.from(attractions.map((x) => x)),
    };
}

这是主要的用户界面和实现

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Index(),
    );
  }
}

class Index extends StatefulWidget {
  @override
  _IndexState createState() => _IndexState();
}

List data;
List<Cities> citylist = List();
List<Cities> citysavedlist = List();
int index;

class _IndexState extends State<Index> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: listView(),
    );
  }

  Future<String> fetchData() async {
    String data =
        await DefaultAssetBundle.of(context).loadString("json/parse.json");
    final jsonResult = json.decode(data);
    this.setState(() {
      jsonResult
          .forEach((element) => citylist.add(new Cities.fromJson(element)));
    });
    return "Success!";
  }

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

  listView() {
    return ListView.builder(
      itemCount: citylist == null ? 0 : citylist.length,
      itemBuilder: (context, index) {
        return Column(
          children: <Widget>[_buildRow(index, citylist)],
        );
      },
    );
  }

  Widget _buildRow(index, citylist) {
    final bool alreadySaved = citysavedlist.contains(citylist[index]);
    return Padding(
      padding: const EdgeInsets.only(top: 5.0, left: 5.0, right: 5.0),
      child: Card(
        child: ListTile(
            title: Text(citylist[index].city, style: TextStyle(fontSize: 22.0)),
            trailing: IconButton(
              icon: Icon(
                alreadySaved ? Icons.star : Icons.star_border,
                color: alreadySaved ? Colors.blue : Colors.blue,
              ),
              onPressed: () {
                setState(() {
                  if (alreadySaved) {
                    citysavedlist.remove(citylist[index]);
                  } else {
                    citysavedlist.add(citylist[index]);
                  }
                });
              },
            ), //subtitle: Text(subtitle),
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => Detail(citylist[index])));
            }),
      ),
    );
  }

  void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          final Iterable<ListTile> tiles = citysavedlist.map(
            (Cities pair) {
              return ListTile(
                  title: Text(
                    pair.city,
                  ),
                  onTap: () {
                    Navigator.push(context,
                        MaterialPageRoute(builder: (context) => Detail(pair)));
                  });
            },
          );

          final List<Widget> divided = ListTile.divideTiles(
            context: context,
            tiles: tiles,
          ).toList();
          return Scaffold(
            appBar: AppBar(
              title: const Text('Saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }
}

class Detail extends StatefulWidget {
  final Cities cities;
  Detail(this.cities);
  @override
  _DetailState createState() => _DetailState();
}

class _DetailState extends State<Detail> {
  List<String> attractionsSavedList = List();

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

    getData();
  }

  /* 

  This is done using the shared Prefrences where the saving structure is String

  This is where key is the unique user id, this is because if you logout with another user then this will differentiate the user and get the string based on it. 

  I have saved  a Map<String,List<String>> as String encoded it and while using it decode the string which will give you the map.
   */

  getData() async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    var stringvalue = sharedPreferences.getString("Id");
    print(stringvalue);
    if (stringvalue != null) {
      Map<String, dynamic> newMap = json.decode(stringvalue);
      print('This is the city selected : ${newMap[widget.cities.city]}');

      var newlist = newMap[widget.cities.city];
      if (newlist != null) {
        newlist.forEach((element) {
          print(element);
          attractionsSavedList.add(element);
        });
      }
    } else {
      print('No values to show');
    }

    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.cities.city),
      ),
      body: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.all(15.0),
                  child: GestureDetector(
                    onTap: () {
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => SavedAttractions()));
                    },
                    child: Text(
                      'Saved Attractions',
                      style: TextStyle(
                        fontSize: 18,
                        decoration: TextDecoration.underline,
                      ),
                    ),
                  ),
                )
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                widget.cities.city,
                style: TextStyle(fontSize: 20),
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: widget.cities.attractions.length,
                itemBuilder: (BuildContext context, int index) {
                  final bool attractionsExists = attractionsSavedList
                      .contains(widget.cities.attractions[index]);
                  return Card(
                      child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(widget.cities.attractions[index]),
                        IconButton(
                          onPressed: () async {
                            SharedPreferences _prefs =
                                await SharedPreferences.getInstance();

                            setState(() {
                              if (attractionsExists) {
                                attractionsSavedList
                                    .remove(widget.cities.attractions[index]);

                                String uniqueid = _prefs.getString("Id");

                                Map<String, dynamic> mapvalue =
                                    json.decode(uniqueid);

                                List list = mapvalue[widget.cities.city];

                                String stringtoRemove;

                                list.forEach((element) {
                                  if (element ==
                                      widget.cities.attractions[index]) {
                                    stringtoRemove =
                                        widget.cities.attractions[index];
                                  }
                                });

                                if (attractionsSavedList.length == 0) {
                                  list.remove(stringtoRemove);

                                  if (list.length == 0) {
                                    mapvalue.remove(stringtoRemove);
                                    _prefs.setString(
                                        "Id", json.encode(mapvalue));
                                  }
                                } else {
                                  list.remove(stringtoRemove);
                                  mapvalue.remove(stringtoRemove);
                                  
                                  mapvalue[widget.cities.city] = list;

                                  _prefs.setString("Id", json.encode(mapvalue));
                                }
                              } else {
                                print(
                                    'It does not exist in the list ${attractionsSavedList.length}');
                                attractionsSavedList
                                    .add(widget.cities.attractions[index]);

                                var uniqueId = _prefs.getString("Id");
                                if (uniqueId != null) {
                                  Map<String, dynamic> newMap =
                                      json.decode(uniqueId);
                                  if (attractionsSavedList.length > 0) {
                                    print(widget.cities.city);

                                    newMap[widget.cities.city] =
                                        attractionsSavedList;
                                    _prefs.setString("Id", json.encode(newMap));
                                  }
                                } else {
                                  if (attractionsSavedList.length > 0) {
                                    Map newMap = Map();
                                    newMap[widget.cities.city] =
                                        attractionsSavedList;
                                    _prefs.setString("Id", json.encode(newMap));
                                  }
                                }

                                /*  {
                                  widget.cities.city: attractionsSavedList
                                }; */

                                attractionsSavedList.forEach((element) {
                                  print(
                                      'This is the list after adding  $element');
                                });
                              }
                            });
                          },
                          icon: Icon(
                            attractionsExists ? Icons.star : Icons.star_border,
                            color:
                                attractionsExists ? Colors.blue : Colors.blue,
                          ),
                        )
                      ],
                    ),
                  ));
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class SavedAttractions extends StatefulWidget {
  @override
  _SavedAttractionsState createState() => _SavedAttractionsState();
}

class _SavedAttractionsState extends State<SavedAttractions> {
  List<String> attractionsList = List();
  bool _isLoading = false;

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

  getSavedAttractions() async {
    setState(() {
      _isLoading = true;
    });
    SharedPreferences preferences = await SharedPreferences.getInstance();

    String value = preferences.getString('Id');

    Map<String, dynamic> newMapVAlue = json.decode(value);

    newMapVAlue.forEach((key, value) {
      value.forEach((elements) {
        attractionsList.add(elements);
      });
    });

    setState(() {
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _isLoading
          ? Center(
              child: CircularProgressIndicator(),
            )
          : ListView.builder(
              itemCount: attractionsList.length,
              shrinkWrap: true,
              itemBuilder: (context, index) {
                return Card(
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text(attractionsList[index]),
                  ),
                );
              }),
    );
  }
}

List<Cities> citiesFromJson(String str) =>
    List<Cities>.from(json.decode(str).map((x) => Cities.fromJson(x)));
String citiesToJson(List<Cities> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Cities {
  Cities({
    this.city,
    this.attractions,
  });

  String city;
  List<String> attractions;

  factory Cities.fromJson(Map<String, dynamic> json) => Cities(
        city: json["city"],
        attractions: List<String>.from(json["attractions"].map((x) => x)),
      );

  Map<String, dynamic> toJson() => {
        "city": city,
        "attractions": List<dynamic>.from(attractions.map((x) => x)),
      };
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章